java垃圾回收算法

java中的所 对象实例都是存放在堆中,垃圾回收器在对堆进行回收之前必须需要知道这些对象有哪些还"存活"着,哪些已经"死去"(不可能再被任何途径使用的对象)。

 

那么怎么确定对象是否存活,有如下一些算法,下面来看看这些算法的异同。

 

1、引用计数算法

 

给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当失去引用时计数器值就减1;任何时刻计数器都为0的对象就是不可能再被使用的。虽然这是个不错的算法,也有一些比较著名的案例使用该算法,如:微软的COM(Component Object Model)技术、使用ActionScript3的flashplayer等而java语言并未使用该算法来管理内存,其主要原因是它很难解决对象间相互循环引用的问题。

 

2、根搜索算法

 

java、c#一些主流的商用程序语言都是采用该算法来判断对象是否存活的。该算法的基本思路就是:通过一系列的名为"GC Roots"的对象作为起始点,从这个节点开始向下搜索,搜索走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时(即从GC Roots到这个对象不可达),则证明此对象是不可用的。所以它们将会被判定为是可回收的对象。

 

java中可以作为GC Roots的对象包括下面几种

 

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

jvm 垃圾 回收算法

 

    1、标记-清除算法

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

       2 复制算法

该算法是为了解决效率问题而出现的。它将可用的内存按容量划分为大小相等的两块,每次只要使用其中的一块。当这一块的内存使用完了就将还存活的对象复制到另一块上面,然后把已使用的内存空间回收,内存分配时也就不用考虑内存碎片等复杂情况了,只要移动堆顶指针,按顺序分配内存即可。该算法的代价就是将内存缩小为原来的一半,未免太高了点。现在多数商用虚拟机都采用收集算法来回收新生代,据ibm专门研究表明,新生代的对象98%都是朝生夕死所以并不需要按照1:1的比例来划分内存空间,而是将内存分为一块较大的Eden和两块较小的survivor空间,每次使用Eden和其中一块survivor。当回收时,将Eden和survivor中还存活着的对象一次性地拷贝到另一个survivor空间上,最后清理掉eden和才用过的survivor的空间。如HotSpot虚拟机默认Eden和survivor的大小比例为8:1,也就是说每次新生代中可用内存空间为整个新生代容量的90%(80%+10% ),只有10%的内存是会被“浪费”的。只有当survivor空间不够用时,需要依赖其他内存(这里指老年代 )进行分配担保。

       3、标记-整理算法

该算法也分为两个阶段,标记过程与标记-清除算法一致。但后续步骤不是直接对可回收的对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存

       4、分代收集算法

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值