原文网址:JVM--Java垃圾收集--内存模型/垃圾收集流程_IT利刃出鞘的博客-CSDN博客
简介本文介绍Java各个代的关系(内存模型)及垃圾收集流程。
内存模型JDK8的内存模型
在Java中所有的垃圾收集问题几乎都是针对堆内存空间完成的,但是要想充分理解垃圾的收集流程,必须首先掌握Java堆内存的最初内存模型组成。如图1所示:
内存模型的变化
JDK1.8以前提供用永久代,而从JDK1.8后永久代被替换为元空间(metaSpace)。在JDK1.8之前,HotSpot都在努力改变永久代的存储位置,例如,在JDK1.6时提供有永久代,到了JDK1.7时又将永久代的部分操作移交给了堆内存,而在JDK1.8时使用元空间代替了永久代。
JDK 1.8之前的内存模型如图2所示。
可以发现,在JDK1.8之前都会提供有永久代,此部分内存是不受GC控制的。在最初的设计中,都将方法区保存在了永久代,所以一旦方法执行中出现了内存不足的情况,将会抛出:“OutOfMemoryError:PermGen space”错误。同时Oracle也在考虑将HotSpot与JRockit(此虚拟机不存在永久代)两个虚拟机合二为一,所以此内存空间被元空间所替代。
垃圾收集流程在整个Java內存模型中,主要有3块内存区:年轻代(Young)、老年代(Tenured)、元空间(metaSpace),同时还会有几块动态调整的内存伸缩区(当几个内存区空间不足时动态扩充)。而JVM的内存回收就是对这几块空间的回收处理操作,对于内存分配与GC的执行流程如图3所示。
上图中的垃圾回收主要是针对年轻代(Eden+Survivor)与老年代(Tenured)完成的。
具体流程如下:
- 当使用关键字new创建一个新对象时,JVM会将新对象保存在Eden区,此时需要判断Eden区是否有空余空间。
- 如果没有,则会执行“MinorGC(年轻代GC)”。如果有,则直接将新对象保存在Edeti区之内;
- 如果此时Eden区的空间依然不足,则会将部分活跃对象保存在Survivor区。如果此时剩余空间可以直接容纳新对象,则会直接为新对象申请内存空间;
- 如果Suivivor有足够的空余空间,则直接保存Eden区晋升的对象。此时Eden区空间得到释放,随后可以在Eden区为新的对象申请内存空间。如果Survivor区空间不足,则需要将Survivor区的部分活跃对象保存到Tenured区。
- 如果此时Tenured区的内存空间也已经满了,则将执行“FullGC”(完全GC或称为MajorGC,其包括年轻代和老年代,相当于使用“Runtime.getRuntime().gc()”处理)以释放年轻代和老年代中保存的不活跃对象。如果在释放后有足够的内存空间,Survivor将保存Eden发送来的对象,这样就可以在Eden区内有足够的内存保存新的对象。
可见,Java在每次创建对象时如果发现内存不足都会自动向其他区域延伸。为了提高性能,在实际应用中可能会开辟尽量大的内存空间,以实现更加合理的GC控制。
其他网址《Java开发实战经典》=> 23.3 JVM垃圾收集



