java具有自动回收垃圾,垃圾回收 Java

  java具有自动回收垃圾,垃圾回收 Java

  JVA垃圾收集机制

  说起垃圾收集(GC),很多人自然会联想到Java。在Java中,程序员不需要关心内存的动态分配和垃圾回收,全部交给JVM。广羽,垃圾收集是指释放垃圾所占据的空间。Java中什么样的对象算是「垃圾」?那么,某些对象确定为垃圾后,采取什么策略回收(释放空间)?当前商用虚拟机有哪些典型的垃圾收集器?让我们逐一讨论这些问题。以下是本文的目录大纲。

  1.如何确认一个物体是“垃圾”?

  二。典型的垃圾收集算法

  三。典型的垃圾收集器

  如有不当之处,敬请原谅批评。我真的很感激。

  请尊重作者的劳动成果,并注明原文链接:

  1.如何确认一个物体是“垃圾”?

  这一节,先了解最基本的问题。判断对象是“垃圾”怎么办?既然垃圾收集器的作用是为新对象回收垃圾对象占用的空间,那么垃圾收集器如何确定对象是“垃圾”呢?这意味着确定可以使用什么方法来回收对象。

  在java中,它通过引用与一个对象相关联。这意味着你必须通过引用来操作对象。一个明显而简单的方法是确定引用计数是否可以回收对象。一般来说,如果一个对象没有关联引用,就意味着这个对象几乎不可能被用在其他地方,它就会成为一个可重用的对象。这种方法是引用计数法。

  这种方法的特点是安装简单高效,但由于不能解决循环引用问题(Python采用引用计数法),所以没有被Java采用。请看下面的代码:

  最后两条语句将空值赋给object1和object2。这意味着您将无法访问object1和object2所指向的对象,但是由于它们相互引用,如果引用计数不为0,垃圾收集器将永远不会回收它们。

  为了解决这个问题,Java采用了可达性分析方法。这种方法的基本思想是以一系列“GC根”对象为起点进行搜索。如果“GC根”和一个对象之间没有可达路径,那么可以说这个对象是不可达的,但是被判断为不可达的对象至少需要经过两次标记过程才能成为可重用对象。如果在这两个标记过程中无法逃脱成为可重用对象的可能性,那么基本上就是真正的可重用对象。

  不清楚可行性分析方法如何操作。如果有熟悉的朋友,请告诉我。

  请看下面的例子:

  在哪一行中对象可能是可重用的?在第七行代码中,对象是可重用的。为什么要让读者自己思考?

  再看另一个例子:

  以下哪三个语句将字符串对象作为可重用对象?第二句,第三句,第二句判断字符串对象在内存不足的情况下可以重用,第三句判断字符串对象在任何情况下都可以重用。

  最后总结了对象经常被判断为可重用对象的情况。

  1)将一个引用赋给null,或者将一个对象的引用赋给一个新的对象,如下面的代码所示:

  2)由局部引用指向的对象。例如,下面的代码:

  每次执行循环时,生成的Object对象都是可重用的对象。

  3)只有弱引用及其相关对象,例如:

  二。典型的垃圾收集算法

  在确认了哪些垃圾可以回收后,垃圾机需要做的就是开始回收垃圾,但是存在一个如何有效回收垃圾的问题。因为Java virtualmachine规范并没有规定如何实现垃圾收集器,不同厂商的虚拟机实现垃圾收集器的方式也不一样,所以这里有一些常见的垃圾收集器。

  1.无奈的高跟鞋-扫(划线-通关)算法

  这是最基本的垃圾收集算法,最基本的原因是它最容易实现,也是最简单的思想。标记-清除算法分为两个阶段:标记阶段和清除阶段。标记阶段的任务是标记所有需要回收的对象,而清理阶段是回收被标记对象占用的空间。该过程如下图所示。

  从图中可以看出,token/clear算法很容易实现,但是存在严重的内存碎片问题。如果碎片太多,后续进程需要为大对象分配空间时,可能找不到足够的空间,从而提前触发新的垃圾收集行为。

  2.复制算法

  为了解决无助高跟鞋扫描算法的缺陷,提出了一种复制算法。根据容量将可用内存分成大小相同的两块,每次只使用其中一块。如果这个块的内存用完了,可以将仍然存在的对象复制到另一个块中,然后一次性清理使用的内存空间,这样就减少了内存碎片问题。该过程如下图所示。

  该算法实现简单,运行高效,并且不容易产生内存碎片。然而,随着可用内存减少一半,它为痴迷于内存空间使用的棒棒糖付出了代价。

  显然,复制算法的效率与活体的数量有很大关系。例如

  如果存活的对象很多,那么复制算法的效率就会大大降低。

  3.无奈的高跟鞋-紧凑(划线-整理)算法

  为了解决复制算法的缺陷,充分利用内存空间,提出了一种无奈的高跟鞋-紧凑算法。这个算法的标记阶段和无奈的高跟鞋-Sweep是一样的,但是标记之后,它不是直接清理可回收的对象,而是把所有幸存的对象都移动到一端,然后清理结束边界以外的内存。具体流程如下图所示:

  4.分代收集算法

  逐代收集算法目前被大多数JVM垃圾收集器使用。其核心思想是根据对象的生命周期将内存划分为几个不同的区域。一般堆区分为老龄代和ssdzh代。年轻一代的特点是每次垃圾收集时只收集少量对象,而ssdzh一代的特点是每次垃圾收集时收集大量对象,因此可以根据不同代的特点采用最合适的收集算法。

  目前大部分垃圾收集器都采用复制算法进行ssdzh生成,因为ssdzh生成中的每一次垃圾收集都会回收大部分对象,也就是说需要复制的操作次数较少,但实际上ssdzh生成的空间并没有按照1: 1的比例划分。一般来说,ssdzh代分为一个较大的伊甸园空间和两个较小的幸存者空间。每使用一次伊甸园空间和一个幸存者空间,回收时,将伊甸园和幸存者中的幸存对象复制到另一个幸存者空间,然后清理掉刚刚使用的伊甸园和幸存者空间。

  而到了老年,每次只回收少量对象,一般使用无奈的高跟鞋-紧凑算法。

  注意堆区之外还有一个代,就是Permanet代,用来存储类类,常量,方法描述等。永久生成的恢复主要包括两部分:丢弃的常量和无用的类。

  三。典型的垃圾收集器

  垃圾收集算法是内存回收的理论基础,垃圾收集器是内存回收的具体实现。这里有一些由热点(JDK 7)虚拟机提供的垃圾收集器。用户可以根据自己的需求,组合不同年龄段使用的采集器。

  1.序列/旧序列

  连载/连载老收藏家是最基础最老的收藏家。它是一个单线程的收集器,当它收集垃圾时,所有的用户线程都必须挂起。串行采集器是针对ssdzh代的采集器,采用复制算法,串行老采集器是针对老年的采集器,采用无奈的高跟鞋-紧凑算法。它的优点是简单高效,缺点是会给用户带来停顿。

  2.帕纽

  PAR collector是串行收集器的多线程版本,它使用多线程进行垃圾收集。

  3.平行扫气

  并行清除收集器是ssdzh代的多线程收集器(并行收集器)。回收时不需要挂起其他用户线程,采用复制算法。该收集器不同于前两个收集器,它主要旨在实现可控的吞吐量。

  4.平行旧

  Parallel Old是Parallel Scavenge collector(并行收集器)的老版本,使用了多线程和无奈的高跟鞋——紧凑算法。

  5.羧甲基淀粉钠

  CMS收集器是一种以获得最短恢复暂停时间为目标的收集器。它是一个并发收集器,采用的是无奈的高跟扫算法。

  6.G1

  G1集热器是集热器技术发展的最先进成果。它是服务器应用程序的收集器,可以充分利用多CPU、多核环境。因此,它是一个并行并发的收集器,可以建立一个可预测的暂停时间模型。

  这里有一些关于内存分配的补充:

  通常,对象的内存分配是在堆上进行的。对象主要分配在伊甸园空间和ssdzh代的From空间,少数情况下会在老年直接分配。如果Eden空间和ssdzh生成空间中没有足够的空间,将启动GC。如果在GC之后,伊甸空间和来自空间可以容纳这些物体,它们将被放置在伊甸空间和来自空间。在GC的过程中,伊甸园空间和From空间中幸存的对象将被移动到to空间,然后伊甸园空间和From空间将被清理。在清理的过程中,如果到空间不足以存放一个物体,就会把这个物体移动到旧时代。GC之后,使用伊甸园空间和To空间。下一次GC将把幸存的对象从空间复制到,依此类推。当一个对象在幸存者区域逃离GC一次,它的年龄就会加1。默认情况下,如果对象达到15岁,它将移动到老年。

  一般来说,大物件会直接分配到老年。所谓大对象是指需要大量连续存储空间的对象。最常见的大型对象是大型数组,例如:

  byte[] data=新字节[4*1024*1024]

  这通常在老年时期直接分配存储空间。

  当然,分配规则并不是100%固定的,这取决于当前使用的垃圾收集器组合以及JVM的相关参数。

  参考资料:

  《深入理解Java虚拟机》

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: