运行时数据区划分
首先java虚拟机JVM在执行程序时,会把内存划分成若干个不同的数据区域。主要有线程共享区(堆区和元空间,JDK1.8前元空间被称为方法区)和线程私有区(程序计数器、虚拟机栈、本地方法栈)。
程序计数器用来记录当前程序的执行行数,控制代码流程。虚拟机栈的局部变量表里存储了基本类型变量值和对象的引用类型,这里的引用会指向堆里的对象实例。所以创键一个对象的实例,几乎都存放在了堆区,在堆区分配内存。
堆区的分代划分
堆区被整体分为1/3新生代和2/3老年代,新生代被分为80%的Eden,和20%的幸存者区from和to(也叫S0和S1)。
创建对象时的内存分配
了解了堆的结构后,以自己的理解来简述一下创建对象时内存分配的具体过程:
创建一个新对象,首先会判断新生代的Eden区是否能放下,如果可以放下:直接分配内存,如果不能放下:需要对Eden区执行YGC(Minor GC)垃圾回收清理策略,没被引用的对象直接被回收,依然存活的旧对象,会判断幸存者区是否能放下,能放下,就防止s1或s0区域,放不下,就判放在老年代里,幸存者区里对象存活时间超过年龄阈值默认15的也晋升到老年代;YGC清理后,再次判断Eden区是否能放下,能放:直接分配内存,放不下:则判断old区(老年区)能否放下,可以放下:直接分配内存;放不下:老年区执行FGC(majirGC 垃圾回收策略),清理后,再次判断老年区是否能放下?能放下:分配内存;放不下,则引发OOM错误(OutOfMemoryError)。
可以根据下图辅助理解: