垃圾回收机制

垃圾回收(garbage collection,简称GC)可以自动清空堆中不再使用的对象。在JAVA中对象是通过引用使用的。如果再没有引用指向该对象,那么该对象就无从处理或调用该对象,这样的对象称为不可到达(unreachable)。垃圾回收用于释放不可到达的对象所占据的内存。

GC的工作流程主要分为如下几个步骤:
1、标记(Mark)
2、计划(Plan)
3、清理(Sweep)
4、引用更新(Relocate)
5、压缩(Compact)

四、什么时候发生GC
1、当应用程序分配新的对象,GC的代的预算大小已经达到阈值,比如GC的第0代已满
2、代码主动显式调用System.GC.Collect()
3、其他特殊情况,比如,windows报告内存不足、CLR卸载AppDomain、CLR关闭,甚至某些极端情况下系统参数设置改变也可能导致GC回收

(一)、标记
目标:找出所有引用不为0(live)的实例
方法:找到所有的GC的根结点(GC Root), 将他们放到队列里,然后依次递归地遍历所有的根结点以及引用的所有子节点和子子节点,将所有被遍历到的结点标记成live。弱引用不会被考虑在内
(二)、计划和清理
1、计划
目标:判断是否需要压缩
方法:遍历当前所有的generation上所有的标记(Live),根据特定算法作出决策
2、清理
目标:回收所有的free空间
方法:遍历当前所有的generation上所有的标记(Live or Dead),把所有处在Live实例中间的内存块加入到可用内存链表中去
(三)、引用更新和压缩
1、引用更新
目标: 将所有引用的地址进行更新
方法:计算出压缩后每个实例对应的新地址,找到所有的GC的根结点(GC Root), 将他们放到队列里,然后依次递归地遍历所有的根结点以及引用的所有子节点和子子节点,将所有被遍历到的结点中引用的地址进行更新,包括弱引用。
2、压缩
目标:减少内存碎片
方法:根据计算出来的新地址,把实例移动到相应的位置。
三、GC的根节点
本文反复出现的GC的根节点也即GC Root是个什么东西呢?
每个应用程序都包含一组根(root)。每个根都是一个存储位置,其中包含指向引用类型对象的一个指针。该指针要么引用托管堆中的一个对象,要么为null。
在应用程序中,只要某对象变得不可达,也就是没有根(root)引用该对象,这个对象就会成为垃圾回收器的目标。
用一句简洁的英文描述就是:GC roots are not objects in themselves but are instead references to objects.而且,Any object referenced by a GC root will automatically survive the next garbage collection.

.NET中可以当作GC Root的对象有如下几种:
1、全局变量
2、静态变量
3、栈上的所有局部变量(JIT)
4、栈上传入的参数变量
5、寄存器中的变量
注意,只有引用类型的变量才被认为是根,值类型的变量永远不被认为是根。只有深刻理解引用类型和值类型的内存分配和管理的不同,才能知道为什么root只能是引用类型。
顺带提一下JAVA,在Java中,可以当做GC Root的对象有以下几种:
1、虚拟机(JVM)栈中的引用的对象
2、方法区中的类静态属性引用的对象
3、方法区中的常量引用的对象(主要指声明为final的常量值)
4、本地方法栈中JNI的引用的对象

  1. 垃圾内存回收算法
    GC为了能够正确释放对象,会监控每个对象的运行状况,对他们的申请、引用、被引用、赋值等状况进行监控,Java会使用有向图的方法进行管理内存,实时监控对象是否可以达到,如果不可到达,则就将其回收,这样也可以消除引用循环的问题。在Java语言中,判断一个内存空间是否符合垃圾收集标准有两个:一个是给对象赋予了空值null,以下再没有调用过,另一个是给对象赋予了新值,这样重新分配了内存空间。
    常见的垃圾回收算法有引用计数法(Reference Counting)、标注并清理(Mark and Sweep GC)、拷贝(Copying GC)和逐代回收(Generational GC)等算法,其中Android系统采用的是标注并删除和拷贝GC,并不是大多数JVM实现里采用的逐代回收算法。由于几个算法各有优缺点,所以在很多垃圾回收实现中,常常可以看到将几种算法合并使用的场景,本节将一一讲解这几个算法。

  2. 引用计数回收法(Reference Counting GC)
    引用计数法的原理很简单,即记录每个对象被引用的次数。每当创建一个新的对象,或者将其它指针指向该对象时,引用计数都会累加一次;而每当将指向对象的指针移除时,引用计数都会递减一次,当引用次数降为0时,删除对象并回收内存。采用这种算法的较出名的框架有微软的COM框架,如代码清单14 - 1演示了一个对象引用计数的增减方式。然而引用计数回收算法有一个很大的弱点,就是无法有效处理循环引用的问题,由于Android系统没有使用该算法,所以这里不做过多的描述,请有兴趣的读者自行查阅相关文档。

  3. 标注并清理回收法(Mark and Sweep GC)
    在这个算法中,程序在运行的过程中不停的创建新的对象并消耗内存,直到内存用光,这时再要创建新对象时,系统暂停其它组件的运行,触发GC线程启动垃圾回收过程。内存回收的原理很简单,就是从所谓的”GC Roots”集合开始,将内存整个遍历一次,保留所有可以被GC Roots直接或间接引用到的对象,而剩下的对象都当作垃圾对待并回收

1.垃圾收集算法的核心思想
java语言提供了自动的GC机制,系统会经常检查内存,采用对象引用计数的方式,将引用次数为0的对象回收。这样可以防止两个危险:(1)防止无用对象占用内存资源 (2)防止有用对象被释放,引起内存非法引用。
2.触发GC(Garbage Collector)的条件
(1)应用进程空闲的时候,GC会回收空闲进程的内存资源。
(2)应用进程繁忙的时候,当需要的内存资源不足的时候, GC会强制执行回收优先级比较低的进程资源,如果还是不足,则再回收两次,还是不足则会报OOM。
3.减少GC开销的措施
(1)尽量少显示地调用 System.gc();
(2)减少临时对象的引用;临时对象退出函数后 ,
(3)对象使用完后,设置为指向null;这样会方便系统查找到空对象,更快回收掉内存;
(4)能用int等基本数据类型,就尽量不要使用Integer等引用类型,基本类型占用的资源比引用类型要小得多;
(5)尽量少地使用static变量。static 变量是全局性的,系统在堆中为其分配内存,GC无法回收该内存;
(6)对于需要使用变长的字符串变量,尽量使用StringBuffer而不是String。String每赋值一次,就会重新分配一次内存,String str = str1+str2+str3+str4+str5,每多一个“+”,就会多
创建一个对象。
(7)分散创建和删除对象的时间。一次性创建或者删除太多的对象,会导致内存突然变得紧张或者一次性释放太对,不利用内存的合理使用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值