垃圾收集机制原理

本文深入探讨了Java垃圾回收机制,介绍了引用计数算法、可达性分析算法等判断对象是否可回收的方法,以及标记-清除、复制、标记-整理、分代收集等垃圾收集算法。同时,讲解了新生代与老年代的区别,以及触发GC回收的条件。
摘要由CSDN通过智能技术生成


Java堆(Java Heap)是Java虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。
Java堆是垃圾收集器管理的主要区域,也被称做“GC堆”(Garbage Collected Heap

Java回收对象涉及如何判断哪些对象应该回收,内存的收集算法等。

1.可回收对象

在堆里面存放着Java世界中几乎所有的对象实例,垃圾收集器在对堆进行回收前,第一件事情就是要确定这些对象之中哪些 可回收。

1、引用计数算法

给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加 1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的,主流的Java虚拟机里面没有选用引用 计数算法来管理内存,其中最主要的原因是它很难解决对象之间相互循环引用的问题。

2、可达性分析算法

是通过一系列的称为"GC Roots"的对象作为起始点,从这些节点开始向 下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连(用图论的话来说,就 是从GC Roots到这个对象不可达)时,则证明此对象是不可用的
在Java语言中,可作为GC Roots的对象包括下面几种:

  1. 虚拟机栈(栈帧中的本地变量表)中引用的对象。
  2. 方法区中类静态属性引用的对象。
  3. 方法区中常量引用的对象。
  4. 本地方法栈中JNI(即一般说的Native方法)引用的对象。

2.垃圾收集算法

垃圾收集算法分为如下:

1.标记-清除算法

“标记-清除”(Mark-Sweep)算法,算法分为“标记”和“清除”两个阶段:首先标记出 所有需要回收的对象,在标记完成后统一回收所有被标记的对象
缺点:
一个是效率问题,标记和清除两个过程的效率都不高;
一个是空间问题,标记清除之后会产生大量不连续的内存碎片, 空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。

2. 复制算法

将可用内存按容量划分为大小相等的两块,每次只使 用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。
现在的商业虚拟机都采用这种收集算法来回收新生代是将内存分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中一块Survivor。当回收时,将Eden和Survivor中还存活着的对象一次性地复制到另外一块Survivor空间上,最后清理掉Eden和刚 才用过的Survivor空间。HotSpot虚拟机默认Eden和Survivor的大小比例是8:1,也就是每次新生代中可用内存空间为整个新生代容量 的90%(80%+10%),只有10%的内存会被“浪费”。

3.标记-整理算法

复制收集算法在对象存活率较高时就要进行较多的复制操作,效率将会变低。根据老年代的特点,有人提出了另外一种“标记-整理”(Mark-Compact)算法,标记过程仍然与“标记-清除”算法一样,但后 续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存,

4. 分代收集算法

当前商业虚拟机的垃圾收集都采用“分代收集”(GenerationalCollection)算法,只是根据对象 存活周期的不同将内存划分为几块。一般是把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算 法。在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制 成本就可以完成收集。而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记—清理”或者“标记— 整理”算法来进行回收。

3.新生代 老年代

Java堆是垃圾收集器管理的主要区域,因此很多时候也被称做“GC堆”(Garbage Collected Heap”)。从内存回收的角度来看,由于现在收集器基本都采用分代收集算法,所以Java堆中还可以细分为:

  • 新生代:有Eden空间、FromSurvivor空间、To Survivor空间等。从内存分配的角度来看,线程共享的Java堆中可能划分出多个线 程私有的分配缓冲区(Thread LocalAllocationBuffer,TLAB)
  • 老年代:主要存放大对象,需要大量连续空间的对象;如长字符串和数组;长期存活的对象直接进入老年代,虚拟机给每个对象定义了一个对象年龄(Age)计数器。如果对象在Eden出生并经过第一次Minor GC后仍然存活,并且能被Survivor容纳的话,将被移动到Survivor空间中,并且对象年龄设为1。对象在Survivor区中每“熬过”一次Minor GC,年龄就增加1岁,当它的年龄增加到一定程度(默认为15岁),就将会被晋升到老年代中。
    为了能更好地适应不同程序的内存状况,虚拟机并不是永远地要求对象的年龄必须达到了MaxTenuringThreshold才能晋升老年 代,如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入 老年代,无须等到MaxTenuringThreshold中要求的年龄。

4.什么时候GC回收对象?

大多数情况下,对象在新生代Eden区中分配。当Eden区没有足够空间进行分配时,虚拟机将发起一次Minor GC,当存活的对象所需要的空间大于survivor空间时,会存入老年代中,当老年代的空间满了,会触发Full GC。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值