咱们从头到尾说一次 Java 垃圾回收

时间:2019-08-02 来源:www.bacdautinh.com

  

我们可以看到,最终,这两个对象不再可访问,但由于它们相互引用,它们的引用计数永远不会为0.通过引用计数算法,它们将永远不会被GC通知。回收它们。

可访问性分析算法

ReachabilityAnalysis的基本思想是使用一些称为参考链(GCRoots)的对象作为从这些节点向下搜索的起点。搜索路径被调用(ReferenceChain),当某个对象未通过任何参考链连接到GCRoots时(即,从GCRoots节点到该节点无法访问),该对象被声明为不可用。

通过可达性算法,成功解决了引用计数无法解决的问题 - “循环依赖”。只要您无法与GCRoot建立直接或间接连接,系统就会确定您是可回收对象。这引出了另一个问题,即GCRoot。

Java内存区域

在Java语言中,以下四种类型的对象可用作GCRoot:

虚拟机堆栈中引用的对象(堆栈框架中的局部变量表)

方法区域中类静态属性引用的对象

方法区域中常量引用的对象

JNI引用的对象(即一般的Native方法)在本地方法堆栈中

1.虚拟机堆栈中引用的对象(堆栈帧中的局部变量表)

这时,s是GCRoot。当s设置为null时,localParameter对象也会使用GCRoot中断参考链,并将被回收。

2,方法区域中类static static引用的对象

s是GCRoot,s设置为null。在GC之后,s指向的属性对象无法再循环,因为它无法与GCRoot建立关系。

而m作为类的静态属性,也属于GCRoot,参数对象仍与GCroot连接,因此此时参数对象不会被回收。

3.方法区域中常量引用的对象

m是方法区域中的常量引用,同样GCRoot,s设置为null,最终对象不会被回收,因为它没有与GCRoot连接。

4.本地方法堆栈中引用的对象

任何本机接口都将使用一些本地方法堆栈。如果使用C连接模型实现本地方法接口,则其本地方法堆栈是C堆栈。当线程调用Java方法时,虚拟机会创建一个新的堆栈帧并将其推送到Java堆栈中。但是,当它调用本地方法时,虚拟机会保持Java堆栈不变,不再将新帧推送到线程的Java堆栈中。虚拟机只是动态连接并直接调用指定的本地方法。

在确定哪些垃圾可以回收之后,垃圾收集器必须开始垃圾收集,但是存在与如何有效地回收垃圾有关的问题。由于Java虚拟机规范没有明确定义如何实现垃圾收集器,因此来自不同供应商的虚拟机可以以不同方式实现垃圾收集器。在这里,我们讨论几种常见垃圾收集算法的核心思想。

马克---清算法

Mark-Sweep算法是最基本的垃圾收集算法。它分为两部分。它首先在内存区域标记这些对象,这些对象是可回收的标记,然后清除它们。如上所示,清理后的垃圾成为未使用的存储区域,等待再次使用。

这种逻辑清晰且易于操作,但它存在一个很大的问题,即内存碎片。

上图中中间块的假设是2M,较小的是1M,较大的是4M。当我们回收它时,内存将被分成许多段。我们知道,当我们打开内存空间时,我们需要一个连续的内存区域。此时,我们需要一个2M的内存区域,并且有两个1M无用。这导致我们拥有如此多的内存,但我们无法使用它。

复制算法

复制算法(Copying)从标记清除算法演化而来,解决了标记清除算法的内存碎片问题。它将可用内存划分为两个大小相等的块,一次只使用其中一个。当该块的内存用完时,将幸存的对象复制到另一块,然后清理一次使用过的内存空间。它确保了内存的连续可用性,并且在分配内存时不需要考虑诸如内存碎片之类的复杂情况。逻辑清晰,操作高效。

上面的图片非常清楚,很明显已经暴露出另一个问题。与我的140平大三居室一起,它只能用作70平方米的小型两居室房子。价格太高了。

标记算法

Mark-Compact标记过程仍然与标记---清除算法相同,但后续步骤不直接清理可循环使用的对象,而是将所有幸存的对象移动到一端,然后清除结束边界。记忆区。

一方面,标记算法在标记清除算法上升级,以解决内存碎片问题,并且还避免了复制算法只能使用一半内存区域的缺点。它看起来不错,但是从上图中可以看出,它更频繁地更改内存,并且需要对所有幸存对象的引用地址进行排序,这比复制算法要糟糕得多。

世代收集算法(GenerationalCollection)不是严格意义或理论,而是上述三种基本算法思想的组合,以及针对不同情况的一组组合拳。对象生命周期的差异将内存分成几个部分。一般来说,Java堆分为新一代和老一代,因此可以根据每个时代的特点采用最合适的收集算法。在新一代中,每次垃圾收集发现大量对象死亡,只有少量生存,那么使用复制算法,只需要支付少量幸存对象复制成本即可完成收集。在过去,由于物体存活率很高并且没有额外的空间来分配它,它必须通过使用标记清洁或标记来回收---------所以,另一个问题来了,什么块的种类是划分的内存区域,每个块的特殊算法是什么?

Java堆(JavaHeap)是JVM管理的最大内存块。堆是垃圾收集器管理的主要区域。这里我们主要分析Java堆的结构。

Java堆主要分为两个领域 - 年轻一代和老年人。年轻一代分为伊甸园区和幸存者区。幸存者区域分为From和To2区域。也许在这个时候每个人都会有疑问,你为什么需要幸存者区,为什么幸存者必须分成两个区域。别担心,我们从头到尾看它,看看对象是如何产生的,以及它为什么没有。

伊甸园区

小发猫的专业研究表明,近98%的对象都在死亡,因此在这种情况下,在大多数情况下,当Eden区域内没有足够的空间用于分发时,对象将被分配到新一代的Eden区域。机器启动MinorGC,这比MajorGC更频繁,并且更快地回收。

在MinorGC之后,伊甸园将被清空,伊甸园地区的大部分物品将被回收,而那些不需要回收的物品将进入幸存者的From区域(如果From区域不够,则直接进入旧区)。

幸存者区

幸存者区域相当于伊甸园和旧区域的缓冲区,类似于交通信号灯中的黄灯。幸存者分为两个区域,一个是From区域,另一个是To区域。每次执行MinorGC时,Eden区域和From幸存对象都被放置在Survivor的To区域中(如果To区域不够,它将直接进入Old区域)。

1.你需要什么?

难道不是老一辈的新一代,直接去老,这是如此的好,它是如此复杂。想想是否没有幸存者区域。每当你在伊甸园区域做一个MinorGC时,幸存的物体就会被送到老年,而老年人很快就会被填满。有很多对象,虽然一旦MinorGC没有被淘汰,但事实上它不会舔Q多久,也许是第二次,第三次需要被清除。在这个时候,进入老年显然不是一个明智的决定。

因此,幸存者的存在是减少发送到老年的对象数量,从而减少MajorGC的发生。幸存者的预筛选保证只有那些在新一代MinorGC中幸存16次的受试者才会被送到老年。

你为什么需要两个?

设置两个Survivor区域的最大好处是解决内存碎片问题。

让我们首先假设如果只有一个区域,幸存者会发生什么。执行MinorGC后,Eden区域被清空,幸存的物体被放置在Survivor区域,并且可能需要清除前一个Survivor区域中的一些物体。问题即将来临,我们如何在此时清除它们?在这种情况下,我们只能标记清理,并且我们知道标记的最大问题是内存碎片。在经常死亡的新一代中,使用标记将不可避免地导致严重的内存碎片。因为幸存者有2个区域,所以MinorGC每次将之前的Eden和From区域中的幸存物体复制到To区域。在第二个MinorGC中,From和To职责被赎回。此时,Eden和To区域中的幸存对象将再次复制到From区域。

这种机制的最大优点是在整个过程中总有一个Survivorspace为空,而另一个非空的Survivorspace是无碎片的。那么,为什么幸存者不会分割更多的碎片呢?例如,如果将幸存者区域细分,则每个部分的空间将很小,这将很容易导致幸存者区域。两个幸存者区域可能是称重后的最佳解决方案。

旧区

老年人占据堆内存空间的2/3,只有在MajorGC期间才会被清理,每次GC都会触发“Stop-The-World”。内存越大,STW越长,因此内存不仅更大,而且更好。由于复制算法在对象存活率高的时候执行了多次复制操作,效率很低,所以这里的老年人就是标记---整理算法。

除此之外,在内存保证机制下,无法放置的对象将直接进入老年,以下情况将进入老年。

1,大物件

大对象是指需要大量连续内存空间的对象。无论是否“死亡”,这部分目标将直接进入老年。这主要是为了避免Eden区域和两个Survivor区域之间的大量内存复制。当你的系统有许多“死在死里”的大物时,你必须要注意。

2.长期存活的物体

虚拟机为每个对象定义对象年龄(Age)计数器。在正常情况下,物体将继续在幸存者的From和To区域之间移动。受试者在幸存者区域没有体验MinorGC,年龄增加1年。当年龄增加到15岁时,它将转移到老年。当然,15,JVM在这里也支持特殊设置。

3.动态对象年龄

虚拟机没有注意对象年龄必须是15岁的要求,并且将被放入老年。如果Survivor空间中相同年龄的所有对象的大小大于Survivor空间,则年龄大于或等于年龄的对象可以直接进入旧区域。无需等待你“成人”。

这实际上有点像负载平衡。轮询是一种负载平衡,确保每台机器获得相同的请求。它似乎很平衡,但每台机器的硬件都不合理,而且健康也不同。我们还可以根据每台机器收到的请求数或每台机器的响应时间来调整负载均衡算法。

本书的部分内容参考了本书:《深入理解Java虚拟机》。

点击这里注册活动!

作者:聂小龙(昵称:率鸽),阿里巴巴高级开发项目。

目前该团队正在疯狂招聘,感兴趣的学生可以发送电子邮件至xiaolong.nxl#alibaba-inc.com,fulan.zjf#alibaba-inc.com。

作者:中间件兄弟

阅读原文

本文是云栖社区的原创内容,未经许可,不得转载。