《深入理解JVM》10-垃圾回收

本系列的第七篇写过一次垃圾回收,今天看起来优点脏乱差,贻笑大方。这节课是对郑雨迪老师的课程总结,希望对大家有点帮助。

第五节的时候我们已经总结过JVM的内存设计了

就是上面这张图,相比大家对这个图已经熟记于心了,我们知道新生成的对象都会被分配到堆这块区域,但是随着系统的不断运行,堆内的对象越来越多,这个时候就要清理一下,回收无用的对象的内存空间,分配给新创建的对象。这就是垃圾回收机制,Java语言能够如此的风靡有很大一部分原因是JVM自带了优秀的垃圾回收器,让开发人员不用关注内存空间分配的问题。

死亡对象辨别方法

  1. 引用计数器算法
  2. 可达性分析算法

最开始的时候,JVM为每个对象提供一个引用计数器,计算指向该对象的引用次数,如果此计数器不为0,表明有使用该对象的其他对象,那么该对象就是存活的。缺点:内存负荷,循环依赖,如下图

为了破解循环依赖的问题,jvm优化了算法,采用可达性分析算法判断对象的存活。算法思想:

  1. 找到虚拟机内一组正在被使用的对象,成为GC root
  2. 从GC root 开始遍历引用路径,只要能随着引用路径到达的对象,就说明对象存活。

如何确定GC root

  1. 当前java方法栈栈帧的局部变量
  2. 被加载到方法区的类的静态变量
  3. JNI handles
  4. 已启动未终止的线程

缺点,在并发的情况下,可能会误遍历不能再到达的对象,比如A线程刚执行完,引用的X对象不会被使用了,但是扫描已经标记该对象为可达的。为了确保正确性,JVM引入了Stop The world 和安全点的概念

Stop the world

stop the world 顾名思义,就是要暂停JVM中所有非垃圾回收的工作,直到垃圾回收完成,这个stop the world 会引起服务暂停,也叫GC pause。内存分配线程发现内存不够用时,会申请JVM进行垃圾回收,提出stop the world请求,虚拟机会等所有的线程进入“安全点”,才允许stop the world进入线程独占工作。

安全点

安全点不是真正的点,也不是让线程暂停,而是进入一种稳定的状态,让GC root不再变动,即JVM的java虚拟机栈帧不再变动,JNI handles不再变动,只要java方法栈的栈帧不再变动,线程还是可以调用当前栈帧中的代码,即不出现java方法栈入栈出栈操作。线程有几种状态:

  1. 解释执行器执行状态,逐条解释执行,可以每条指令检查安全点
  2. 即时编译器执行状态,只有在方法回边的时候检查安全点
  3. 阻塞状态:因为java线程调用在JVM管制范围内,所以安全

垃圾回收的三种方式

清除:把死亡的对象删除

压缩:把死亡的对象删除,并且移动存活的对象到内存一侧

复制:把内存分为两部分,每次只用一份,内存不够时,把使用部分的或对象复制到另外一部分内存,并清理回收当前内存空间

分代思想

对象存活的时间:

根据统计,jvm中的对象按照2-8定律,80%的对象存活的时间极短,只有20%的对象存活的时间很长,所以,80%的对象需要频繁GC,另外的20%不要,那么把这两部分对象分开GC可以获得更好的GC效果,这就是分代思想。

年轻代:新创建的对象,存放在年轻代

老年代:经历过默认15次年轻代GC的对象,存放在老年代

年轻代的GC使用的复制方法,把年轻代分为3部分,Eden/Survivor/Survivor三个部分,空间大小8:1:1。

存活的对象被复制到Survivor1区,GC完之后,Survivor1的对象复制到2中,回收Eden和Survivor1,下次GC继续这么操作。Survivor区的对象经历过15次这样的GC之后,会被移动到老年代。

老年代如果引用了年轻代的对象,在Minor GC的时候,岂不是要遍历所有的老年代,这不意味着要全堆扫描,为了省略遍历老年代的时间,引入卡表的概念

卡表:

把对内存分为大小相同的区域,每个区域新建一块卡片,存储对象引用信息,那么就意味着要在所有的写操作写入该卡片,JVM引入写入 屏障 write barrier,这个屏障写卡片信息,非常的快。

新生代的垃圾回收器

  1. Serial :单线程的标记-复制
  2. Paralle Scavenge:跟Parallel差不多,但是更注重吞吐量。不能与CMS共同使用
  3. Parallel New 多线程的标记-复制

老年代垃圾回收器

  1. Serial Old:单线的标记压缩
  2. Parallel Old:多线程的标记压缩
  3. CMS:标记删除,随着G1的发展,CMS在java9之后废弃

G1回收器

已经打乱了分代的思想,把堆内存划分为多个内存区域,每个区域维护一个内存分配情况表,当内存不够时,有限回收内存中垃圾占比较大的空间。所以叫Garbage First

猜你喜欢

转载自blog.csdn.net/David_lou/article/details/109103434