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

时间:2019-08-09 来源: 星座
兴发pt官方

2509688-cd0e57a40617cf2d.jpg

在我上学之前,我有这个。我说我在自助餐厅吃饭。吃完菜后,我是一名C ++程序员。吃完饭之后,我还是一名Java程序员。

实际上,在Java世界中,似乎我们不必专注于垃圾收集。许多初学者不了解GC,仍然可以编写一个更好的程序或系统。但实际上这并不意味着Java的GC并不重要。相反,存在问题是如此重要和复杂。那些初学者除了打开GC日志并查看一堆0101天文学外无法做任何事情。

今天我们将从头到尾谈论Java垃圾收集。

垃圾收集(GC),顾名思义,释放垃圾占用的空间并防止内存泄漏。有效利用可用内存来清理和回收已在内存堆中死亡或长时间未使用的对象。

在Java语言出现之前,每个人都在拼命编写C或C ++程序。这时,存在很大的矛盾。 C ++和其他语言创建对象应该不断打开空间。不使用时,他们需要不断释放控件。构造函数和析构函数都被写入,并且多次重复,然后被破坏。因此,有人建议你可以编写一个程序来实现这个功能。每次创建和释放控件时,都可以重复使用此代码而无需重复。

1960年,基于麻省理工学院的Lisp首次提出了垃圾收集的概念,用于处理C语言等不间断的破坏性操作。这时,Java尚未诞生!所以事实上GC并不是Java的专利,GC的历史远远大于Java的历史!

由于我们要进行垃圾收集,我们必须首先弄清楚垃圾的定义是什么以及需要回收哪些内存。

参考计数算法

可达性计数算法通过在对象标题中指定空格(引用计数)来保存引用对象的次数。如果该对象被另一个对象引用,则其引用计数将增加1.如果删除对该对象的引用,则其引用计数减1.当对象的引用计数为0时,该对象将被回收。

String m=new String('jack');

首先创建一个字符串,这次'jack'有一个引用,即m。

2509688-224f3d33e5b8392e.png

然后将m设置为null,然后对'jack'的引用数等于0.在引用计数算法中,这意味着需要回收内容。

米=NULL;

2509688-ca65067dd263eb38.png

引用计数算法将垃圾收集分发到整个应用程序,而不是暂停垃圾收集,直到堆中所有对象的处理结束。因此,使用引用计数的垃圾收集并不严格地是“Stop-The-World”垃圾收集机制。

它看起来非常好,但我们知道JVM的垃圾收集是“Stop-The-World”。是什么原因导致我们最终放弃了引用计数算法?看下面的例子。

1.定义2个对象

2.互相参考

3.清空各自的索赔参考

2509688-4d6b5d39c6786847.png

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

可访问性分析算法

可达性分析的基本思想是使用一些名为GC Roots的对象作为从这些节点向下搜索的起点。搜索的路径称为(参考链)。如果对象未连接到没有任何引用链的GC根(即,从GC根节点到节点无法访问),则该对象被证明不可用。

2509688-71b8696c644c9ae5.jpeg

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

Java内存区域

在Java语言中,以下对象可用作GC根:

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

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

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

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

2509688-4a85c52b9682c9e8.png

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

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

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

s是GC Root,s设置为null。在GC之后,s指向的属性对象被回收,因为它无法与GC Root建立关系。

并且m作为类的静态属性,也属于GC Root,参数对象仍然连接到GC根,因此此时参数对象不会被回收。

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

m是方法区域中的常量引用。此外,在GC Root之后,s设置为null,最终对象将不会被回收,因为它未连接到GC Root。

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

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

2509688-4655320b02030639.png

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

标记---清除算法

2509688-f0b8851d5a2644b6.png

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

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

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

复制算法

2509688-b8d44113e0c63075.png

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

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

标记算法

2509688-47c7cd235972564a.png

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

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

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

2509688-b29260e813120f9b.png

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

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

伊甸园区

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

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

幸存者区

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

1.你需要什么?

是不是老一辈的新生代?直接去伊甸园不好吗?它太复杂了。想象一下,如果没有幸存者区域,每次在伊甸园区域进行小型GC时,幸存的物体将被送到老年,而老年人很快就会被填满。有很多对象,虽然Minor GC没有被破坏,但它不会持续很长时间。也许第二次,第三次需要清除。在这个时候,进入老年显然不是一个明智的决定。

因此,幸存者的存在是减少发送到老年的对象数量,从而减少主要GC的发生。幸存者的预先筛选保证只有那些幸存下来的第16次小型GC才能在新一代中存活下来的人将被送到老年时期。

你为什么需要两个?

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

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

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

旧区

老年人占据堆内存空间的2/3,只在主要GC期间清理,每次GC触发“Stop-The-World”。内存越大,STW越长,因此内存不仅更大,而且更好。由于复制算法在对象存活率高的情况下在老年时执行多次复制操作,因此效率非常低,因此这里的老年人使用标记整理算法。

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

1,大物件

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

2.长期存活的物体

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

3.动态对象年龄

虚拟机不注意目标年龄必须为15岁的要求,并将进入老年。如果幸存者空间中同一年龄的所有物体的总年龄大于幸存者空间的年龄,则年龄大于或等于此年龄的物体可直接进入旧区域。无需等待你“成人”。

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

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

2509688-098237190cc35d6f.png

点击这里注册活动!

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

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

作者:中间件兄弟

阅读原文

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

新闻排行
  1. 4月27日广州教育新闻制高点马兴瑞主持了全省第一季度经济形势。马兴瑞强调,要抓好下一步经济工作,必须坚?

    4月27日广州教育新闻制高点马兴瑞主持了全省第一季度经济形势。马兴瑞强调,要抓好下一步经济工作,必须坚?...

  2.   孩子成长的每一个细节都得到家长的关注,亲子餐厅的出现让家长放心,孩子外出用餐没烦恼,考拉小厨推出

      孩子成长的每一个细节都得到家长的关注,亲子餐厅的出现让家长放心,孩子外出用餐没烦恼,考拉小厨推出...

  3.   孩子成长的每一个细节都得到家长的关注,亲子餐厅的出现让家长放心,孩子外出用餐没烦恼,考拉小厨推出

      孩子成长的每一个细节都得到家长的关注,亲子餐厅的出现让家长放心,孩子外出用餐没烦恼,考拉小厨推出...

  4. 文|上官青曼-01-虽然婚姻可以带来生命,但如果一个女人失去自我,生活就会变得苍白。婚姻和家庭永远不是女?

    文|上官青曼-01-虽然婚姻可以带来生命,但如果一个女人失去自我,生活就会变得苍白。婚姻和家庭永远不是女?...

  5. 在《上瘾》之后,还没有播出另一部剧,优于《镇魂》?作为一个小小的系列,每天都会给你带来美丽的戏剧,三

    在《上瘾》之后,还没有播出另一部剧,优于《镇魂》?作为一个小小的系列,每天都会给你带来美丽的戏剧,三...

  6. 全屋地板进化论:全实木场景体验,打造核心区,增进家的向心力!    房子不是家,有人才是家。  一家

    全屋地板进化论:全实木场景体验,打造核心区,增进家的向心力!    房子不是家,有人才是家。  一家...

  7. 没有哭过的月份是最快乐的,月份可以避免“低落情绪”,你的“生活”非常好这位家庭的长者警告他们坐在月球

    没有哭过的月份是最快乐的,月份可以避免“低落情绪”,你的“生活”非常好这位家庭的长者警告他们坐在月球...

  8.   最美的ShowGirl,最好玩的电竞花边,带你直击2019ChinaJoy。    ChinaJoy是中国最大的动漫游戏展会

      最美的ShowGirl,最好玩的电竞花边,带你直击2019ChinaJoy。    ChinaJoy是中国最大的动漫游戏展会...

  9. 2019-07-1119:40来源:试用图书网络今年,猫已出版书籍?今年,猫已出版书籍?上面的图片显示了净红橙色猫点

    2019-07-1119:40来源:试用图书网络今年,猫已出版书籍?今年,猫已出版书籍?上面的图片显示了净红橙色猫点...

  10.   ?NB游戏,娱乐生活!大家好,我是NB。地下城和战士M在1月3日悄然启动了测试,可能不适合许多小伙伴。NB

      ?NB游戏,娱乐生活!大家好,我是NB。地下城和战士M在1月3日悄然启动了测试,可能不适合许多小伙伴。NB...