首页 > 试题广场 >

介绍一下分代回收机制

[问答题]
推荐

得分点

​ 新生代收集、老年代收集、混合收集、整堆收集

参考答案

标准回答

​ 当前商业虚拟机的垃圾收集器,大多数都遵循了“分代收集”的理论进行设计,分代收集名为理论,实质是一套符合大多数程序运行实际情况的经验法则。而分代收集理论,建立在如下三个分代假说之上,即弱分代假说、强分代假说、跨代引用假说。依据分代假说理论,垃圾回收可以分为如下几类:

  1. 新生代收集:目标为新生代的垃圾收集。
  2. 老年代收集:目标为老年代的垃圾收集,目前只有CMS收集器会有这种行为。
  3. 混合收集:目标为整个新生代及部分老年代的垃圾收集,目前只有G1收集器会有这种行为。
  4. 整堆收集:目标为整个堆和方法区的垃圾收集。

加分回答

​ HotSpot虚拟机内置了很多垃圾收集器,其中针对新生代的垃圾收集器有Serial、ParNew、Parallel Scavenge,针对老年代的垃圾收集器有CMS、Serial Old、Parallel Old。此外,HotSpot还内置了面向整堆的G1收集器。在上述收集器中,常见的组合方式有:

  1. Serial + Serial Old,是客户端模式下常用的收集器。
  2. ParNew + CMS,是服务端模式下常用的收集器。
  3. Parallel Scavenge + Parallel Old,适用于后台运算而不需要太多交互的分析任务。

延伸阅读

​ 三个分代假说:

  1. 弱分代假说:绝大多数对象都是朝生夕灭的。
  2. 强分代假说:熬过越多次垃圾收集过程的对象越难以消亡。
  3. 跨代引用假说:跨代引用相对于同代引用来说只占极少数。

​ 前两条假说奠定了多款常用垃圾收集器的一致的设计原则:收集器应该将Java堆划分出不同的区域,然后将回收对象依据其年龄分配到不同的区域之中存储。根据这两条假说,设计者一般至少会把Java堆划分为新生代和老年代两个区域。在新生代中,每次垃圾收集时都发现有大批对象死去,而每次回收后存活的少量对象,将会逐步晋升到老年代中存放。

​ 第三条假说是根据前两条假说推理得出的隐含结论:存在互相引用关系的两个对象,是应该倾向于同时生存或者同时消亡的。依据这条假说,我们就不应再为了少量的跨代引用去扫描整个老年代,也不必浪费空间专门记录每一个对象是否存在及存在哪些跨代引用,只需在新生代上建立一个全局的数据结构,这个结构把老年代划分成若干小块,标识出老年代的哪一块内存会存在跨代引用。

编辑于 2021-09-15 10:44:07 回复(0)
GC算法分别包括标记-清除,标记-整理,复制算法以及分代回收四种(其实是三种)。
标记-清除:将空间里的对象进行扫描,挂掉的进行一个标记,然后对其进行统一回收,缺点是容易造成空间碎片化,当有大对象放入时可能会再次触发垃圾回收机制;
标记-整理:清理的过程和之前一样,只不过在清理后会整体对空间进行整理,将对象再次排列。缺点是效率低;
复制算法:将内存空间一分为二,也就是Suevivor区的from和to两部分,每次只使用一个,当使用的空间触发垃圾回收以后,将所有存活对象复制到另一部分,然后将使用的空间直接全部清除干净。
分代回收:这个一般是说指jvm的GC算法,在新生代使用复制算法,老生代使用标记-整理或标记-清除算法。
发表于 2022-09-09 15:02:21 回复(1)

JVM 将运行时数据区分为五个部分:

  • 堆(Heap):线程共享
  • 方法区(Method Area):线程共享
  • 程序计数器(Program Counter Register):线程私有
  • 虚拟机栈(Java Virtual Machine Stack):线程私有
  • 本地方法栈(Native Method Stack):线程私有

在堆中,会经常进行垃圾回收。堆的内存通常被划分为:

  • 新生代(Young Generation):通常包括 Eden 区和两个 Survivor 区(S0 和 S1)。在新生代的垃圾回收中,称为 Minor GC,通常使用复制算法。
  • 老年代(Old Generation):在老年代的垃圾回收中,称为 Major GC 或 Old GC,通常使用标记-整理算法、标记-清除算法
发表于 2024-08-24 20:53:07 回复(0)
垃圾分代回收机制
JVM对自己的内存进行了划分5个区域,分别是
方法栈:所有的方法运行的时期,进行的内存;
堆(heap):存储的是容器和对象。
寄存器:内存和CPU之间;
本地方法栈:JVM调用了系统中的功能;
方法和数据共享:运行时期class文件,进行的地方;
垃圾分代回收机制针对的是堆内存。
Java中的每种数据类型大小都是确定的,所以所有的内存是由Java自己进行分配,这也就意味着内存的管理和回收也是由JVM自己进行。在Java中一旦产生内存问题导致程序员无法处理。理论上在正常情况下Java中的堆内存是足够使用的,当堆内存使用的负荷量超过一定限度(一般情况下是70%)的时候,会启动垃圾回收器(Garbage Collector — GC)进行堆内存的回收释放。
分代是指堆内存又分为新生代(Young Generation)与老生代(Old Generation),新生代又分为伊甸园区(eden)与幸存区(survivor),幸存区由from space与to space两块相等的内存区域构成。
eden:from:to = 8:1:1

如图,对象在刚创建的时候是先放入新生代中的伊甸园区;如果在伊甸园区经过一次回收依然存在,那么将这个对象挪到幸存区,在幸存区中经过多次回收这个对象依然存在则挪到老生代。在回收的时候先回收新生代,如果新生代回收之后的内存足够使用则不扫描老生代;如果不够则扫描老生代。老生代的扫描频率要低于新生代。
发生在新生代的回收 — 初代回收(minor gc)
发生在老生代的回收 — 完全回收(full gc)
对象创建完成之后会先试图放入新生代;如果新生代经过回收之后也放不开,则直接试图将该对象放入老生代。老生代如果也放不开,则会出现错误 — OutOfMemoryError。
发表于 2021-12-13 11:34:14 回复(3)