垃圾回收 - 分代垃圾回收

这篇具有很好参考价值的文章主要介绍了垃圾回收 - 分代垃圾回收。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

分代垃圾回收在对象中导入了“年龄”的概念,通过优先回收容易成为垃圾的对象,提高垃圾回收的效率。

1、新生代对象和老年代对象

分代垃圾回收中把对象分类成几代,针对不同的代使用不同的 GC 算法,我们把刚生成的对象称为新生代对象,到达一定年龄的对象则称为老年代对象。
众所周知,新生代对象大部分会变成垃圾。如果我们只对这些新生代对象执行 CC会怎么样呢?除了引用计数法以外的基本算法,都会进行只寻找活动对象的操作(如标记清除算法的标记阶段和 复制算法等)。因此,如果很多对象都会死去,花费在 GC上的时间应该就能减少。
我们将对新对象执行的 CC 称为新生代 GC (minor GC)。mainor 在这里的意思是“小规模的”。新生代 GC 的前提是大部分新生代对象都没存活下来,GC 在短时间内就结束了。
另一方面,新生代 GC 将存活了一定次数的新生代对象当作老年代对象来处理。我们把类似于这样的新生代对象上升为老年代对象的情况称为晋升 (promotion).。
因为老年代对象很难成为垃圾,所以我们对老年代对象减少执行 GC 的频率。相对于新生代GC,我们将面向老年代对象的 GC 称为老年代 GC (major CC)。
在这里有一点需要注意,那就是分代垃圾回收不能单独用来执行 GC。我们需要把它和之前介绍的基本算法结合在一起使用,来提高那些基本算法的效率。
也就是说,分代垃圾回收不是跟GC 标记一清除算法和 GC 复制算法并列在一起供我们选择的算法,而是需要跟这些基本算法一并使用。

2、Unger的分代垃圾回收

在Ungar 的分代垃圾回收中,堆的结构如下图所示。我们总共需要利用 4个空间,分别是生成空间、2个大小相等的率存空间以及老年代空间,并分别用 new_start、survivor1_start、survivor2_start、old_start 这4 个变量引用它们的开头。我们将生成空间和幸存空间合称为新生代空间。新生代对象会被分配到新生代空间,老年代对象则会被分配到老年代空间里。Ungar 在论文里把生成空间、幸存空间以及老年代空间的大小分别设成了 140K字节、28K 字节和 940K宇节。
此外我们准备出一个和堆不同的数组,称为记录集(remembered set),设为rs。

垃圾回收 - 分代垃圾回收,垃圾回收与内存泄漏,jvm,java,算法

生成空间就如它的字面意思一样,是生成对象的空间,也就是进行分配的空间。当生成空间满了的时候,新生代 GC 就会启动,将生成空间中的所有活动对象复制,这跟GC 复制算法是一个道理。目标空间是幸存空间。
2个幸存空间和CC复制算法里的 From 空间、To 空间很像,我们经常只利用其中的一个。在每次执行新生代 GC 的时候,活动对象就会被复制到另一个幸存空间里。在此我们将正在使用的幸存空间作为 From 幸存空间,将没有使用的幸存空间作为To幸存空间。
不过新生代GC 也必须复制生成空间里的对象。也就是说,生成空间和 From 幸存空间这两个空间里的活动对象都会被复制到To幸存空间里去。这就是新生代 CC。
只有从一定次数的新生代 CC 中存活下来的对象才会得到晋升,也就是会被复制到老年代空间去。
垃圾回收 - 分代垃圾回收,垃圾回收与内存泄漏,jvm,java,算法

分代垃圾回收的优点是只将垃圾回收的重点放在新生代对象身上,以此来缩减GC所需要的时间。不过考虑到从老年代对象的引用,结果还是要搜索堆中的所有对象,这样一来就大大削减了分代垃圾回收的优势。所以就利用到了——记录集。
记录集用来记录从老年代到新生代对象的引用。这样新生代GC就可以不搜索老年代空间的所有对象,只通过搜索记录集来发现从老年代到新生代对象的引用。

3、记录集

记录集被用于高效地寻找从老年代对象到新生代对象的引用。具体来说,在新生代GC时将记录集看成根,并进行搜索,以发现指向新生代空间的指针。
垃圾回收 - 分代垃圾回收,垃圾回收与内存泄漏,jvm,java,算法

记录集基本上是用固定大小的数组来实现的。各个元素是指向对象的指针。
那么,我们该怎么往记录集里记录对象呢?这就是下一节要介绍的“写入屏障”了。

4、写入屏障

在分代垃圾回收中,为了将老年代对象记录到记录集里,我们利用写入屏障 (write barrier)。在mutator 更新对象间的指针的操作中,写入屏障是不可或缺的。write_barrier()函数的伪代码如下所示。这个函数跟引用计数法中出现的 update_ptr()函数是在完全相同的情况下被调用的。

write_barrier (obj, field, new_obj){
	if (obj >= $old_start && new_obj < $old_start && obj.remembered == false)
		$rs [$rs-indez] = obj
		$rs_index++
		obj.remembered = true
	*field = new_obj
}

参数obj是发出引用的对象,obj 内存在要更新的指针,而 field指的就是 obj 内的域。new_obj 是在指针更新后成为引用目标的对象。
if判断主要是检查以下三点:

  • 发出引用的对象是不是老年代对象
  • 指针更新后的引用的目标对象是不是新生代对象
  • 发出引用的对象是否还没有被记录到记录集中

当这些检查结果都为真时,obj 就被记录到记录集中了。

5、对象的结构

在Ungar 的分代垃圾回收中,对象的头部中除了包含对象的头部中类和大小之外,还有以下这3条信息:

  • 对象的年龄(age)
  • 已经复制完成的标志(forwarded)
  • 已经向记录集记录完毕的标志(remembered)

age表示的是对象从新生代 CC 中存活下来的次数,这个值如果超过一定次数(AGE_MAX),对象就会被当成老年代对象处理。我们在 CC 复制算法和 GC标记压缩算法中也用到过 forwarded, 这里它的作用是一样的,都是用来防止重复复制相同对象的标志。这里的remembered也一样,是用来防止向记录集中重复记录的标志。不过 remembered只用于老年代对象,age 和forwarded只用于新生代对象。
此外,跟GC复制算法一样,在这里我们也使用forwarding指针。在torvrarting 指针中利用obj.field1,用obj.forwarding 访问 obj.field1.
Ungar 的分代垃圾回收中用到的对象的结构如下图所示
垃圾回收 - 分代垃圾回收,垃圾回收与内存泄漏,jvm,java,算法

6、分配

分配是在生成空间进行的。执行分配的new_obj()函数如下所示

new_obj (size){
	if ($new_free + size ›= $survivor1_start)
		minor_gc ()
		if ($new_free + size ›= $survivor1_start)
			allocation_fail ()
 		}
	obj = $new_free
	$new_free += size
	obj.age = 0
	obj.forwarded = false
	obj.remembered = false
	obi.size = size
	return obj
}

7、优缺点

优点:吞吐量得到改善
缺点:在部分程序中会起到反作用。“很多对象年纪经轻就会死”这个法则毕竟只适合大多数情况,并不适用于所有程程序。当然、对象会活得很久的程序也有很多。对这样的程序执行分代垃圾回收,就会产生以下两个问题文章来源地址https://www.toymoban.com/news/detail-712610.html

  • 新生代GC所花费的时间增多
  • 老年代GC频繁运行
    而且,写入屏障导致的额外负担降低了吞吐量。只有当新生代GC 带来的速度提升效果大于写入屏障对速度造成的影响时,分代垃级回收才能够更好地发挥作用。当这个大小关系不成立时,分代址圾回收就没有什么作用,或者说反而可能会起到反作用。这种情况下我们还是使用基本算法更好。

到了这里,关于垃圾回收 - 分代垃圾回收的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • JVM学习 GC垃圾回收机制 (堆内存结构、GC分类、四大垃圾回收算法)

    🤖 作者简介: 努力的clz ,一个努力编程的菜鸟 🐣🐤🐥   👀 文章专栏: 《JVM 学习笔记》 ,本专栏会专门记录博主在学习 JVM 中学习的知识点,以及遇到的问题。   🙉 文章详情: 本篇博客是学习 【狂神说Java】JVM快速入门篇 的学习笔记,关于 GC垃圾回收机制 (堆内存结

    2023年04月19日
    浏览(31)
  • 3.Java面试题—JVM基础、内存管理、垃圾回收、JVM 调优

    一篇文章掌握整个JVM,JVM超详细解析!!! JVM (Java虚拟机) 是运行 Java 字节码 的 虚拟机 。 JVM 针对 不同系统 有 特定实现 ( Windows 、 Linux 等),目的是 同样的代码 在 不同平台 能运行出 相同的结果 。 Java 语言 要经过 编译 和 解释 两个步骤: 编译 :通过 编译器 将 代码 一

    2024年02月15日
    浏览(39)
  • JVM | 垃圾回收器(GC)- Java内存管理的守护者

    在编程世界中, 有效的内存管理 是至关重要的。这不仅确保了应用程序的稳定运行,还可以大大提高性能和响应速度。作为世界上最受欢迎的编程语言之一,通过Java虚拟机内部的垃圾回收器组件来自动管理内存,是成为之一的其中一项必不可少的技术点。 在许多传统的编程

    2024年02月09日
    浏览(39)
  • 深入探讨Java虚拟机(JVM):执行流程、内存管理和垃圾回收机制

    目录 什么是JVM? JVM 执行流程 JVM 运行时数据区 堆(线程共享) Java虚拟机栈(线程私有) 什么是线程私有? 程序计数器(线程私有) 方法区(线程共享) JDK 1.8 元空间的变化 运行时常量池 内存布局中的异常问题 1.  Java堆溢出 2.  虚拟机栈和本地方法栈溢出 JVM 类加载 1.

    2024年02月09日
    浏览(36)
  • 【Java】图解 JVM 垃圾回收(一):GC 判断策略、引用类型、垃圾回收算法

    垃圾 是指运行程序中 没有任何引用指向的对象 ,需要被回收。 内存溢出 :经过垃圾回收之后,内存仍旧无法存储新创建的对象,内存不够溢出。 内存泄漏 :又叫 “ 存储泄漏 ”,对象不会再被程序使用了,但是 GC 又不能回收它们。例如:IO 流不适用了但是没有被 Close、

    2024年02月19日
    浏览(38)
  • 【Java虚拟机】JVM垃圾回收机制和常见回收算法原理

    1.垃圾回收机制 (1)什么是垃圾回收机制(Garbage Collection, 简称GC) 指自动管理动态分配的内存空间的机制,自动回收不再使用的内存,以避免内存泄漏和内存溢出的问题 最早是在1960年代提出的,程序员需要手动管理内存的分配和释放 这往往会导致内存泄漏和内存溢出等问

    2024年02月02日
    浏览(38)
  • java面经03-虚拟机篇-jvm内存结构&垃圾回收、内存溢出&类加载、引用&悲观锁&HashTable、引用&finalize

    要求 掌握 JVM 内存结构划分 尤其要知道方法区、永久代、元空间的关系 结合一段 java 代码的执行理解内存划分 执行 javac 命令编译源代码为字节码 执行 java 命令 创建 JVM,调用类加载子系统加载 class,将类的信息存入 方法区 创建 main 线程,使用的内存区域是 JVM 虚拟机栈 ,

    2024年02月09日
    浏览(40)
  • 【Java高级应用:深入探索Java编程的强大功能,JVM 类加载机制, JVM 内存模型,垃圾回收机制,JVM 字节码执行,异常处理机制】

    本人详解 作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》 公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题 中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯 转载说明:务必注明来源(注明:作者:

    2024年01月16日
    浏览(76)
  • 垃圾回收 - 分代垃圾回收

    分代垃圾回收在对象中导入了“年龄”的概念,通过优先回收容易成为垃圾的对象,提高垃圾回收的效率。 分代垃圾回收中把对象分类成几代,针对不同的代使用不同的 GC 算法,我们把刚生成的对象称为新生代对象,到达一定年龄的对象则称为老年代对象。 众所周知,新生

    2024年02月08日
    浏览(28)
  • jvm垃圾回收及内存模型

    1、了解垃圾回收之前,必须先了解内存模型 jdk1.8后,元空间是 方法区的具体实现 (方法区是规范,之前叫永久代)   1)运行时常量池  就是字节码生成的Class对象包含上述的常量池       2、垃圾回收区域    a、 首先要标记垃圾,找出垃圾      b、Java垃圾回收(一)_java 垃

    2024年02月08日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包