JVM的堆是運行時數據區,所有類的實例和數組都是在堆上分配內存。它在JVM啟動的時候被創建。對象所占的堆內存是由自動內存管理系統也就是垃圾收集器回收。
堆內存是由存活和死亡的對象組成的。存活的對象是應用可以訪問的,不會被垃圾回收。死亡的對象是應用不可訪問尚且還沒有被垃圾收集器回收掉的對象。一直到垃圾收集器把這些對象回收掉之前,他們會一直占據堆內存空間。
永久代是用於存放靜態文件,如Java類、方法等。持久代對垃圾回收沒有顯著影響,但是有些應用可能動態生成或者調用一些class,例如Hibernate 等,在這種時候需要設置一個比較大的持久代空間來存放這些運行過程中新增的類,永久代中一般包含:
- 類的方法(字節碼...)
- 類名(Sring對象)
- .class文件讀到的常量信息
- class對象相關的對象列表和類型列表 (e.g., 方法對象的array).
- JVM創建的內部對象
- JIT編譯器優化用的信息
虛擬機中的共划分為三個代:
年輕代(Young Generation)、年老代(Old Generation)和持久代(Permanent
Generation)。其中持久代主要存放的是Java類的類信息,與垃圾收集要收集的Java對象關系
不大。年輕代和年老代的划分是對垃 圾收集影響比較大的。
- 年輕代:
所有新生成的對象首先都是放在年輕代的。年輕代的目標就是盡可能快速的收集掉那些生
命周期短的對象。年輕代分三個區。一個Eden區,兩個 Survivor區(一般而言)。大部分對象在
Eden區中生成。當Eden區滿時,還存活的對象將被復制到Survivor區(兩個中的一個),當這
個 Survivor區滿時,此區的存活對象將被復制到另外一個Survivor區,當這個Survivor去也滿了
的時候,從第一個Survivor區復制過來的並且此時還存活的對象,將被復制“年老區
(Tenured)”。需要注意,Survivor的兩個區是對稱的,沒先后關系,所以同一個區中可能同時
存在從Eden復制過來對象,和從前一個Survivor復制過來的對象,而復制到年老區的只有從第
一個Survivor去過來的對象。而且,Survivor區總有一個是空的。同時,根據程序需要,
Survivor區是可以配置為多個的(多於兩個),這樣可以增加對象在年輕代中的存在時間,減
少被放到年老代的可能。
- 年老代:
在年輕代中經歷了N次垃圾回收后仍然存活的對象,就會被放到年老代中。因此,可以認
為年老代中存放的都是一些生命周期較長的對象。
- 持久代:
用於存放靜態文件,如今Java類、方法等。持久代對垃圾回收沒有顯著影響,但是有些應
用可能動態生成或者調用一些class,例如Hibernate 等,在這種時候需要設置一個比較大的持
久代空間來存放這些運行過程中新增的類。持久代大小通過-XX:MaxPermSize=<N>進行設置。
用可能動態生成或者調用一些class,例如Hibernate 等,在這種時候需要設置一個比較大的持
久代空間來存放這些運行過程中新增的類。持久代大小通過-XX:MaxPermSize=<N>進行設置。
注意:
JDK1.8中,永久代已經從java堆中移除,String直接存放在堆中,類的元數據存儲在meta space中,meta space占用外部內存,不占用堆內存。
可以說,在java8的新版本中,持久代已經更名為了元空間(meta space)。