资讯专栏INFORMATION COLUMN

Java的GC机制

ruicbAndroid / 2786人阅读

摘要:分代收集主要针对这两类的对象进行回收。伊甸园空间执行后,将和活着的对象一次性复制到另一个名为的中去,然后清理和执行多次后,依然存活的对象会被转移至老年代。在年轻代存活对象占用的内存超过时,则多余的对象会放入年老代。

jvm 中,程序计数器、虚拟机栈、本地方法栈都是随线程而生随线程而灭,栈帧随着方法的进入和退出做入栈和出栈操作,实现了自动的内存清理,因此,我们的内存垃圾回收主要集中于 堆和方法区中,在程序运行期间,这部分内存的分配和使用都是动态的。

GC算法: 对象存活判断

引用计数法:每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收。
缺点是无法释放循环引用的对象。如下图:

根搜索算法:从GC Roots开始向下搜索,搜索所走过的路径称为引用链。当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。
在Java语言中,GC Roots包括:
虚拟机栈中引用的对象。
方法区中类静态属性实体引用的对象。
方法区中常量(final)引用的对象。
本地方法栈中JNI引用的对象。


可以看到,该算法可以释放循环引用的对象(D和E)。

垃圾收集算法

标记/清除算法:当堆中的有效内存空间(available memory)被耗尽的时候,就会停止整个程序(也被成为stop the world),然后进行两项工作,第一项则是标记,第二项则是清除。

(1)标记:标记的过程其实就是,遍历所有的GC Roots,然后将所有GC Roots可达的对象标记为存活的对象。
(2)清除:清除的过程将遍历堆中所有的对象,将没有标记的对象全部清除掉。

缺点:1、首先,它的缺点就是效率比较低(递归与全堆对象遍历),而且在进行GC的时候,需要停止应用程序,这会导致用户体验非常差劲
2、第二点主要的缺点,则是这种方式清理出来的空闲内存是不连续的(碎片化),JVM就不得不维持一个内存的空闲列表,这又是一种开销。而且在分配数组对象的时候,寻找连续的内存空间会不太好找。

复制(copying)算法:将内存划分为两个区间,所有动态分配的对象都只能分配在其中一个区间(称为活动区间),而另外一个区间(称为空闲区间)则是空闲的,当有效内存空间耗尽时,JVM将暂停程序运行,开启复制算法GC线程。将活动区间内的存活对象,全部复制到空闲区间,且严格按照内存地址依次排列,与此同时,GC线程将更新存活对象的内存引用地址指向新的内存地址。此时,空闲区间已经与活动区间交换,而垃圾对象现在已经全部留在了原来的活动区间。事实上,在活动区间转换为空间区间的同时,垃圾对象已经被一次性全部回收。

缺点:1、它浪费了一半的内存。
2、如果对象的存活率很高,我们可以极端一点,假设是100%存活,那么我们需要将所有对象都复制一遍,并将所有引用地址重置一遍。复制这一工作所花费的时间,在对象存活率达到一定程度时,将会变的不可忽视。

标记/整理算法:标记/整理算法与标记/清除算法非常相似,它也是分为两个阶段:标记和整理。

(1)标记:它的第一个阶段与标记/清除算法是一模一样的,均是遍历GC Roots,然后将存活的对象标记。

(2)整理:移动所有存活的对象,且按照内存地址次序依次排列,然后将末端内存地址以后的内存全部回收。因此,第二阶段才称为整理阶段。
优点:标记/整理算法不仅可以弥补标记/清除算法当中,内存区域分散的缺点,也消除了复制算法当中,内存减半的高额代价。
缺点:效率也不高,不仅要标记所有存活对象,还要整理所有存活对象的引用地址。从效率上来说,标记/整理算法要低于复制算法。

总结:1、三个算法都基于根搜索算法去判断一个对象是否应该被回收,而支撑根搜索算法可以正常工作的理论依据,就是语法中变量作用域的相关内容。因此,要想防止内存泄露,最根本的办法就是掌握好变量作用域,
2、在GC线程开启时,或者说GC过程开始时,它们都要暂停应用程序(stop the world)。
3、性能比较
效率:复制算法>标记/整理算法>标记/清除算法(此处的效率只是简单的对比时间复杂度,实际情况不一定如此)。
内存整齐度:复制算法=标记/整理算法>标记/清除算法。
内存利用率:标记/整理算法=标记/清除算法>复制算法。

分代收集算法

GC分代的基本假设:绝大部分对象的生命周期都非常短暂,存活时间短。
GC将对象数据进行分类。主要是两类:年轻代(Young Generation),老年代(Old Generation)。分代收集主要针对这两类的对象进行回收。

年轻代(Young Generation):年轻代含两种结构,伊甸园空间(1个,占80%)和幸存空间(2个,各占10%)。大多数对象会很快的变得不可达,因此,很多对象会在变成年轻代之后就消失,而这个过程我们称之为“ minor GC”。由于存活率低,选用复制算法,一旦发生GC,将10%的幸存区间与另外80%伊甸园空间中存活的对象转移到10%的幸存空间,接下来,将之前90%的内存全部释放。

年轻代遵循以下规则:
通常刚刚被创建的对象会存放在伊甸园空间。
伊甸园空间执行GC后,将Eden和From活着的对象一次性复制到另一个名为To的Survivor中去,然后清理Eden和From

执行GC多次后,依然存活的对象会被转移至老年代。

老年代(old Generation):对象来自新生代,如上所说部分对象会不可达,而剩下的从年轻代中存活下来,被拷贝至老年代。老年代所占用的空间要比年轻代多。如上,对象在老年代也会消失,而这个过程被称之为“major GC”(或者是 “full GC”).老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记-清除”或“标记-整理”算法来进行回收。

Permanebt Generation :持久代,或者称为方法区(method area),通常持久代用来保存类常量以及字符串常量。而特别需要注意这个持久代区域不是用来保存从老年代存活下来的对象的。持久代也可以发生GC。同时这个区域的GC会被看待为 major GC.(使用“标记-清除”或“标记-整理”算法)
永久代主要回收两种:常量池中的常量,无用的类信息。
要知道常量的回收是相对简单的,主要是无用的类回收比较麻烦,要注意以下几点:
类的实例已经全部被回收了
ClassLoader已经被回收
类的对象没有被引用

通常情况下,以下两种情况发生的时候,对象会从新生代区域转到年老带区域。
1、在年轻代里的每一个对象,都会有一个年龄,当这些对象的年龄到达一定程度时(年龄就是熬过的GC次数,每次GC如果对象存活下来,则年龄加1),则会被转到年老代,而这个转入年老代的年龄值,一般在JVM中是可以设置的。

2、在年轻代存活对象占用的内存超过10%时,则多余的对象会放入年老代。这种时候,年老代就是新生代的“备用仓库”。

参考文章:
https://www.cnblogs.com/sunfi...
http://www.cnblogs.com/ityouk...
http://blog.csdn.net/u0116690...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/68546.html

相关文章

  • 细述 Java垃圾回收机制→How Java Garbage Collection Works?

    摘要:当一个实例被创建的时候,它最初被存放在堆内存空间的年轻代的区中。老年代或者永久代是堆内存的第二个逻辑部分。在垃圾回收过程中扫描属于部分的堆内存。一旦实例从堆内存中删除了,它们原来的位置将空出来给以后分配实例使用。 本文非原创,翻译自How Java Garbage Collection Works?在Java中为对象分配和释放内存空间都是由垃圾回收线程自动执行完成的。和C语言不一样的是...

    cc17 评论0 收藏0
  • Java性能优化之垃圾回收机制

    摘要:年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。年老代在年轻代中经历了次垃圾回收后仍然存活的对象,就会被放到年老代中。什么情况下触发垃圾回收由于对象进行了分代处理,因此垃圾回收区域时间也不一样。 [TOC] 与C/C++相比,java语言不需要程序员直接控制内存回收,java程序的内存分配和回收都是由JRE在后台自动进行,JRE会负责回收那些不再使用的内存,这种机制被称为垃圾...

    philadelphia 评论0 收藏0
  • 乐字节Java|GC垃圾回收机制、package和import语句

    摘要:本文接上一篇乐字节关键字关键字块。本文是接着讲述垃圾回收机制和语句。一垃圾回收机制全名垃圾回收机制程序员无权调用垃圾回收器。通知运行,但是规范并不能保证立刻运行。若缺省该语句,则指定为无名包。 本文接上一篇:乐字节Java|this关键字、static关键字、block块。本文是接着讲述JavaGC垃圾回收机制、package 和 import语句。showImg(https://se...

    xuexiangjys 评论0 收藏0
  • 金三银四面试季节之Java 核心面试技术点 - JVM 小结

    摘要:直接对栈的操作只有两个,就是对栈帧的压栈和出栈。中将永久代移除,同时增加元数据区。在中,本地方法栈和虚拟机栈是在同一块儿区域,这完全取决于技术实现的决定,并未在规范中强制。 原文:https://github.com/linsheng97... 描述一下 JVM 的内存区域 程序计数器(PC,Program Counter Register)。在 JVM 规范中,每个线程都有它自己的...

    XGBCCC 评论0 收藏0
  • Java虚拟机:Java自动内存管理和回收机制

    摘要:所以我们提到的内存回收大都是指堆内存的回收。根据堆内存对对象的代的划分我们对堆内存有这样划分各版本和种类的垃圾回收器各有其用武之地,配合使用它们得到最好的效果十分重要。 这篇文章的素材来自周志明的《深入理解Java虚拟机》。作为Java开发人员,一定程度了解JVM虚拟机的的运作方式非常重要,本文就一些简单的虚拟机的相关概念和运作机制展开我自己的学习过程。 虚拟机内存分区 java虚拟机...

    xuxueli 评论0 收藏0
  • 译文-java垃圾回收机制

    摘要:原文出处垃圾回收机制标记清除算法介绍最主要的理论算法之一,在实践过程中,为了真实情景需要,需要许多调整。因此不会仅仅标记清除,垃圾回收期间,内存整理进程同时在工作。不同内存区域的垃圾收集机制不辣么容易理解。 原文出处:java垃圾回收机制 标记清除算法介绍最主要的理论算法之一,在实践过程中,为了真实情景需要,需要许多调整。举一个简单例子,我们检查JVM需要做的各种事情,以便我们安全地去...

    Warren 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<