JAVA的JVM的內存可分為3個區:堆(heap)、堆棧(stack)和方法區(method)


http://blog.hesey.net/2011/04/introduction-to-java-virtual-machine.html

 

 

JAVA的JVM的內存可分為3個區:堆(heap)、堆棧(stack)和方法區(method)

  • 堆區:

    1. 提供所有類實例和數組對象存儲區域

    2. jvm只有一個堆區(heap)被所有線程共享,堆中不存放基本類型和對象引用,只存放對象本身

  • 棧區:

    1. 每個線程包含一個棧區,棧中只保存基礎數據類型的對象和自定義對象的引用(不是對象),對象都存放在堆區中

    2. 每個棧中的數據(原始類型和對象引用)都是私有的,其他棧不能訪問。

  • 方法區:

    1. 又叫靜態區,跟堆一樣,被所有的線程共享。方法區包含所有的class和static變量。

    2. 方法區中包含的都是在整個程序中永遠唯一的元素,如class,static變量。

    3. 運行時常量池都分配在 Java 虛擬機的方法區之中

 

 

堆區:
1.存儲的全部是對象,每個對象都包含一個與之對應的class的信息。(class的目的是得到操作指令)
2.jvm只有堆區(heap)和方法區(下面)被所有線程共享,堆中不存放基本類型和對象引用,只存放對象本身.
3.一般由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回收 。

棧區:  
1.每個線程包含一個棧區,棧中只保存基礎數據類型的對象和自定義對象的引用(不是對象),對象都存放在堆區中
2.每個棧中的數據(原始類型和對象引用)都是私有的,其他棧不能訪問。
3.棧分為3個部分:基本類型變量區、執行環境上下文、操作指令區(存放操作指令)。
4.由編譯器自動分配釋放 ,存放函數的參數值,局部變量的值等.

靜態區/方法區:
1.方法區又叫靜態區,跟堆一樣,被所有的線程共享。方法區包含所有的class和static變量。
2.方法區中包含的都是在整個程序中永遠唯一的元素,如class,static變量。
3.全局變量和靜態變量的存儲是放在一塊的,初始化的全局變量和靜態變量在一塊區域, 未初始化的全局變量和未初始化的靜態變量在相鄰的另一塊區域。

類型信息和類的靜態變量都存儲在方法區中。方法區中對於每個類存儲了以下數據:

a.類及其父類的全限定名(java.lang.Object沒有父類)

b.類的類型(Class or Interface)

c.訪問修飾符(public, abstract, final)

d.實現的接口的全限定名的列表

e.常量池

f.字段信息

g.方法信息

h.靜態變量

i.ClassLoader引用

j.Class引用

 

可見類的所有信息都存儲在方法區中。由於方法區是所有線程共享的,所以必須保證線程安全,舉例來說,如果兩個類同時要加載一個尚未被加載的類,那么一個類會請求它的ClassLoader去加載需要的類,另一個類只能等待而不會重復加載。

此外為了加快調用方法的速度,通常還會為每個非抽象類創建私有的方法表,方法表是一個數組,存放了實例可能被調用的實例方法的直接引用。方法表對於多態有非常重要的意義,具體可以參照《淺談多態機制的意義及實現》一文中“多態的實現”一節。

在Sun JDK中,方法區對應了持久代(Permanent Generation),默認最小值為16MB,最大值為64MB。 

 

 

1:棧

   在函數中定義的一些基本類型的變量數據和對象的引用變量都在函數的棧內存中分配。  

   當在一段代碼塊定義一個變量時,Java就在棧中為這個變量分配內存空間,當該變量退出該作用域后,Java會自動釋放掉為該變量所分配的內存空間,該內存空間可以立即被另作他用。

   每個線程包含一個棧區,每個棧中的數據(原始類型和對象引用)都是私有的,其他棧不能訪問。棧分為3個部分:基本類型變量區、執行環境上下文、操作指令區(存放操作指令)。

2:堆

   堆內存用來存放由new創建的對象和數組。 在堆中分配的內存,由Java虛擬機的自動垃圾回收器來管理。在堆中產生了一個數組或對象后,在棧中定義一個特殊的變量,讓棧中這個變量的取值等於數組或對象在堆內存中的首地址,棧中的這個變量就成了數組或對象的引用變量。  引用變量就相當於是為數組或對象起的一個名稱,以后就可以在程序中使用棧中的引用變量來訪問堆中的數組或對象。引用變量就相當於是為數組或者對象起的一個名稱。引用變量是普通的變量,定義時在棧中分配,引用變量在程序運行到其作用域之外后被釋放。而數組和對象本身在堆中分配,即使程序運行到使用 new 產生數組或者對象的語句所在的代碼塊之外,數組和對象本身占據的內存不會被釋放,數組和對象在沒有引用變量指向它的時候,才變為垃圾,不能在被使用,但仍然占據內存空間不放,在隨后的一個不確定的時間被垃圾回收器收走(釋放掉)。這也是java比較占內存的原因。實際上,棧中的變量指向堆內存中的變量,這就是java中的指針! 

   Java的堆是一個運行時數據區,類的對象從中分配空間。這些對象通過new、newarray、anewarray和multianewarray等指令建立,它們不需要程序代碼來顯式的釋放。堆是由垃圾回收來負責的,堆的優勢是可以動態地分配內存大小,生存期也不必事先告訴編譯器,因為它是在運行時動態分配內存的,Java的垃圾收集器會自動收走這些不再使用的數據。但缺點是,由於要在運行時動態分配內存,存取速度較慢。

   jvm只有一個堆區(heap)被所有線程共享。

3、方法區(method area)

   方法區跟堆一樣,被所有的線程共享。用於存儲虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯后的代碼等數據。

4、常量池(constant pool)

   常量池指的是在編譯期被確定,並被保存在已編譯的.class文件中的一些數據。除了包含代碼中所定義的各種基本類型(如int、long等等)和對象型(如String及數組)的常量值(final)還包含一些以文本形式出現的符號引用,比如:類和接口的全限定名; 字段的名稱和描述符; 方法和名稱和描述符。虛擬機必須為每個被裝載的類型維護一個常量池。常量池就是該類型所用到常量的一個有序集和,包括直接常量(string,integer和floating point常量)和對其他類型,字段和方法的符號引用。對於String常量,它的值是在常量池中的。而JVM中的常量池在內存當中是以表的形式存在的,對於String類型,有一張固定長度的CONSTANT_String_info表用來存儲文字字符串值,注意:該表只存儲文字字符串值,不存儲符號引用。說到這里,對常量池中的字符串值的存儲位置應該有一個比較明了的理解了。在程序執行的時候,常量池會儲存在方法區(Method Area),而不是堆中。

 

   棧的優勢是,存取速度比堆要快,僅次於寄存器,棧數據可以共享(指的是線程共享,而給進程共享)。但缺點是,存在棧中的數據大小與生存期必須是確定的,缺乏靈活性。棧中主要存放一些基本類型的變量數據(int, short, long, byte, float, double, boolean, char)和對象句柄(引用)。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM