1、概念
JVM根据对象存活周期不同,把堆内存划分为年轻代、老年代、持久代。其中持久代主要存放的是Java类的类信息,与垃圾收集要收集的Java对象关系不大。年轻代和年老代的划分是对垃圾收集影响比较大的。
2、分代原因
堆内存存放对象实例,是JVM管理的内存中最大一块,也是垃圾回收最频繁的一块。分代是为了提高对象内存分配和垃圾回收的效率。
3、堆(Heap)和非堆(Non-heap)内存
堆是在Java虚拟机启动时创建的。在JVM中堆之外的内存称为非堆内存(Non-heap memory)”。 可以看出JVM主要管理两种类型的内存:堆和非堆。 简单来说堆就是Java代码可及的内存,是留给开发人员使用的;非堆就是JVM留给自己用的。
所有新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。年轻代分三个区。一个Eden区,两个Survivor区(一般而言)。 大部分对象在Eden区中生成。当Eden区满时,还存活的对象将被复制到SurvivorA区(两个中的一个),当SurvivorA区满时,此区的存活对象将被复制到另外一个SurvivorB区,当SurvivorB区也满了的时候,从第一个SurvivorA区复制过来的并且此时还存活的对象,将被复制“年老区(Tenured)”。需要注意,Survivor的两个区是对称的,没先后关系,所以同一个区中可能同时存在从Eden复制过来对象,和从前一个Survivor复制过来的对象,而复制到年老区的只有从第一个Survivor去过来的对象。而且,Survivor区总有一个是空的。同时,根据程序需要,Survivor区是可以配置为多个的(多于两个),这样可以增加对象在年轻代中的存在时间,减少被放到年老代的可能。
默认的所占空间比例年轻代(Young generation) :老年代(Old generation) = 1 :2
一个伊甸园空间(Eden)和 两个幸存者空间(SurvivorA、SurvivorB)
默认新生代空间的分配:Eden : SurvivorA : SurvivorB = 8 : 1 : 1
经过n次垃圾回收存活的对象(这个n被称为年龄阀值 ,默认是15次)。 老年代空间的构成其实很简单,它不像新生代空间那样划分为几个区域,它只有一个区域,里面存储的对象并不像新生代空间绝大部分对象都是朝闻道,夕死矣。这里的对象几乎都是从Survivor 空间中熬过来的,它们绝不会轻易的狗带。因此,Full GC(Major GC)发生的次数不会有Scanvage GC(Minor GC)那么频繁,并且做一次 Full GC 的时间比Scanvage GC 要更长(约10倍)。
JDK1.8后变成元空间,元空间不再占用堆中的空间。而持久代却是在堆中开辟空间,用于存放静态文件、类信息等,一般不做GC。