20

JVM垃圾回收(上)

 4 years ago
source link: https://www.tuicool.com/articles/fQ7vQbM
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Java 中的垃圾回收,常常是由 JVM 帮我们做好的。虽然这节省了大家很多的学习的成本,提高了项目的执行效率,但是当项目变得越来越复杂,用户量越来越大时,还是需要我们懂得垃圾回收机制,这样也能进行更深一步的优化。

<!-- more -->

辨别对象存亡

垃圾回收( Garbage Collection,以下简称 GC ),从字面上理解,就是将已经分配出去的,但却不再使用的内存回收回来,以便能够再次分配。

在 JVM 中,垃圾就是指的死亡对象所占据的堆空间( GC 是发生在堆空间中),那么我们如果辨别一个对象是否死亡呢?JVM 使用的是 引用计数法可达性分析

引用计数法

引用计数法( Reference Counting),是为每个对象添加一个引用计数器,用来统计引用该对象的个数。一旦某个对象的引用计数器为0,则说明该对象已经死亡,便可以被回收了。

其具体实现为:

如果有一个引用,被赋值为某一对象,那么将该对象的引用计数器 +1。

如果一个指向某一对象的引用,被赋值为其他值,那么将该对象的引用计数器 -1。

也就是说,我们需要截获所有的引用更新操作,并且相应地增减目标对象的引用计数器。

看似很简单的实现,其实里面有不少缺陷:

  1. 需要额外的空间来存储计数器。
  2. 计数器的更新操作十分繁琐。
  3. 最重要的:无法处理循环引用对象。

针对第3点,举个例子特别说明一下:

假设对象 a 与 b 相互引用,除此之外没有其他引用指向他们。在这种情况下,a 和 b 实际上已经死了。

但由于它们的引用计数器皆不为0(因为相互引用,两者均为1),在引用计数法的计算中,这两个对象还活着。因此,这些循环引用对象所占据的空间将不可回收,从而造成了 内存泄露

可达性分析

可达性分析( Reachability Analysis ),是目前 JVM 主要采取的判定对象死亡的方法。实质在于将一系列 GC Roots 作为初始的存活对象合集(live set),然后从该合集出发,探索所有能够被该集合引用到的对象,并将其加入到该集合中,这个过程我们也称之为标记(mark)。最终,未被探索到的对象便是死亡的,是可以回收的。

那么什么是 GC Roots 呢?我们可以暂时理解为由堆外指向堆内的引用,一般而言,GC Roots 包括(但不限于)如下几种:

  1. Java 方法栈桢中的局部变量
  2. 已加载类的静态变量
  3. JNI handles
  4. 已启动且未停止的 Java 线程

之前我们说 引用计数法 会有循环引用的问题, 可达性分析 就不会了。举例来说,即便对象 a 和 b 相互引用,只要从 GC Roots 出发无法到达 a 或者 b,那么可达性分析便会认为它们已经死亡。

可达性分析 有没有什么缺点呢?有的,在多线程环境下,其他线程可能会更新已经分析过的对象中的引用,从而造成误报(将引用设置为 null)或者漏报(将引用设置为未被访问过的对象)。

误报并没有什么伤害,JVM 至多损失了部分垃圾回收的机会。漏报则比较麻烦,因为垃圾回收器可能回收事实上仍被引用的对象内存。一旦从原引用访问已经被回收了的对象,则很有可能会直接导致 JVM 崩溃。

STW

既然 可达性分析 在多线程下有缺点,那 JVM 是如何解决的呢?答案便是 Stop-the-world(以下简称 JWT ),停止了其他非垃圾回收线程的工作直到完成垃圾回收。这也就造成了垃圾回收所谓的暂停时间(GC pause)。

那 SWT 是如何实现的呢?当 JVM 收到 SWT 请求后,它会等待所有的线程都到达安全点(Safe Point),才允许请求 SWT 的线程进行独占的工作。

那什么又叫安全点呢?安全点是 JVM 能找到一个稳定的执行状态,在这个执行状态下,JVM 的堆栈不会发生变化。

这么一来,垃圾回收器便能够“安全”地执行可达性分析,所有存活的对象也都可以成功被标记,那么之后就可以将死亡的对象进行垃圾回收了。

总结

以上便是发现死亡对象的过程,这也为之后的垃圾回收进行铺垫,具体的垃圾回收过程,我会在下一篇文章中讲述,敬请期待。

有兴趣的话可以访问我的博客或者关注我的公众号、头条号,说不定会有意外的惊喜。

https://death00.github.io/

ARRNv2V.jpg!web

FVreii7.jpg!web

本文由博客一文多发平台 OpenWrite 发布!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK