python 查看引用计数数法与GC Root可达性分析法区别

休闲娱乐生活服务其他类别扫扫有惊喜
JVM如何判定对象为垃圾对象(可被GC回收的对象)?一、判定对象为垃圾对象的两种算法引用计数法可达性分析法二、引用计数法给对象中添加一个引用计数器,当有地方引用这个对象的时候,引用计数器值+1,引用失效的时候,引用计数器值-1;当值为0时,就被判定为垃圾对象。引用计数法知识点:若让对象1的引用=让他不再对对象1进行引用,那么此算法垃圾回收是不会对对象1,2,3进行回收的,因为他们彼此之间互相引用,引用计数器值都不为0。这就产生了内存泄漏。很明显当前主流虚拟机采取的不是此算法。三、可达性分析法采取的是类似树的结构,上下级互相链接,若中间断开了链接,则他自己以及他下面全部节点都会被回收。
上一页&1共2页热门新闻更多
实时热点榜单热门视频
阅读下一篇视频推荐503 Service Temporarily Unavailable
503 Service Temporarily Unavailable&|&&|&&|&&|&&
当前位置: >
深入理解Java虚拟机----(三)内存分配策略和垃圾收集器
作者:wl6965307 & 来源:转载 &
摘要: 垃圾回收:
垃圾回收面临着三个问题:回收什么、什么时候回收、怎么回收。
哪些对象已经不再被需要了,就需要被回收。引用计数法:教科书式解释,每个对象维护对它的引用的个数。但是主流虚拟机不适用,因为难解决循环引用。可达性分析算法:主流适用的算法。虚拟机选定一些GCRoot对象,如果一个对象和GCRoot对象间没有引用链,则这个对象是无用的、可以回收的。可以作为GCRoot的有:虚拟机栈中引用的对
垃圾回收:
& &&垃圾回收面临着三个问题:回收什么、什么时候回收、怎么回收。
& & 哪些对象已经不再被需要了,就需要被回收。
引用计数法:教科书式解释,每个对象维护对它的引用的个数。但是主流虚拟机不适用,因为难解决循环引用。
可达性分析算法:主流适用的算法。虚拟机选定一些GCRoot对象,如果一个对象和GCRoot对象间没有引用链,则这个对象是无用的、可以回收的。可以作为GCRoot的有:
虚拟机栈中引用的对象
方法区中,类静态属性引用的对象
方法区中常量引用的对象
本地方法栈中引用的对象
& & 这两种方法都和引用相关。JDK1.2对引用进行了扩充:
强引用:代码常用的引用,存在就不会被回收
软引用:有用但非必须的引用。如果快OOM了,会把这部分对象进行回收。SoftReference
弱引用:非必须引用。只能活到下一次回收之前。WeakReference
虚引用:不会对生存时间有影响。唯一作用是可以在对象被回收时受到通知。PhantomReference
& & 可达性分析过后,如果一个对象和GCRoot间没有可达的引用链了,它并不是立即被回收。首先要看它有没有finalize()方法,有的话被没被执行过。如果有而且没执行过,把它放到一个F-Queue队列,虚拟机一个单独的线程区调用对象的finalize方法。但是并不保证一定执行完。对象可以在这个方法中救自己--给自己一个引用。如果没救成功,则就被回收了。救成功的对象,再次被可达性分析筛选为可回收时,不会再执行fianlize,
因为只会被执行一次!
finalize方法代价高、不确定性大,
非常不建议使用
& & 方法区----常说的HotSport中的永久代,也可以被回收,但是效果通常不如堆好。而且堆内对象不使用了一定会回收,而方法区是可以被回收,是有差别的!字面常量等比较容易处理,没有引用就可以被回收。而类回收条件酒比较严苛:
类的所有实例对象已经被回收
加载类的ClassLoader已经被回收
没有对该类对象的引用
& & 可以使用-Xnoclassgc控制。大量使用反射、动态代理、动态JSP等的系统,建议开启,防止方法区溢出。
& & 垃圾收集算法:
标记清除:基础算法。标记的方法上面说过了。这个算法的缺点是会产生不连续的内存碎片,导致明明有很多内存剩余,但由于新对象太大,没有足够的连续空间而引发又一次的GC。
复制算法:将空间划分为相等的两块区域,当前的满了,就把存活的对象复制到第二块块,整齐排列,然后在第二块开始为新对象分配内存。好处是解决了标记清除的碎片问题,但代价太大----内存缩小一半。商业虚拟机绝大部分采用这种算法回收新生代,但新生代一般98%的对象都是很快死掉,所以不用1:1的分配,而是将新生代分为一块eden和两块survivor,每次把eden和一块survivor的存活对象复制到另一块,回收剩下的。默认比例eden:suvivor = 8:1,所以这种方法只有10%的空间被“浪费”。但是,我们并不能保证存活下来的对象永远少于新生代10%的大小,如果不够了,需要依赖老年代分配担保。
标记整理算法:像老年代这种区域,对象的存活率较高复制算法的效率就会比较低。而且不想浪费50%就要分配担保,所以老年代一般不使用复制算法。标记整理是标记后,将存活对象移动到一端,将剩下的内存清理。
分代收集算法:分代只是将整个内存区域划分为几个小区域,可以在每个区域上选择各自的收集算法。例如新生代,大多短命,采用复制算法。老年代存活率高,没有额外空间担保,采用标记清除或标记整理。
HotSport实现:
& & 虚拟机实现必须保证高效、准确。HotSport在下面几个方面的实现方法:
枚举根节点:虚拟机必须对一个一致性快照分析才能准确,不能一边分析一边还在变,所以枚举根节点要暂停所有线程(Stop-The-World)。如果挨个的分析方法区和栈中的引用,会非常耗时,HotSport用一个叫做OopMap的结构记录了这些信息,从而可以直接快速的拿到数据。
安全点SafePoint:OopMap的状态随时都会改变,不可能为每条指令都生成OopMap,所以定义了安全点的概念。只有在安全点才能生成OopMap,才能暂停线程进行回收。安全点选择原则是方法调用、循环跳转、异常跳转等具有让程序长时间执行的特征的指令。
安全区域:安全点的方案,在线程不分配cpu时间的情况下,如sleep,就无法走到安全点暂停,GC就被卡住了,这时需要安全区域解决。安全区域是指在一个区域内,引用关系不会发生变化,任意位置开始GC都是可以的。离开安全区域时,需要等GC枚举根节点结束。
垃圾收集器:
& & 垃圾收集器是上面介绍的垃圾收集算法的具体实现。在HotsSport中包含以下几种:
& & 先解释:并行是指多个收集线程并行,并发是收集线程和用户线程同时执行。
& & 这7中作用于不同的代,连线表示可以配合使用。
Serial:最基本的单线程收集器。而且会暂停所有线程直到收集结束。Serial作用于新生代用复制算法。它有弊端,但是是现在client模式下的默认新生代收集器。
ParNew:就是Serial的多线程并行版本。除了多线程,其他与Serial一模一样,复制算法,暂停所有线程。是新生代收集器的首选,可以与CMS配合使用。
Parallel Seavenge:也是作用于新生代复制算法的实现。区别是追求的是吞吐量,可以参数设置最大停顿时间和吞吐量。收集器会收集系统信息,自动调节各区域大小、比例等来优化,达到设定的目标。
SerialOld:是Serial的老年代版本,单线程,标记整理算法。主要用于client模式。另一个用途是作为CMS的后备方案。
Parallel&Old:Parallel Seavenge的老年代版本,标记整理算法。
CMS:追求最短停顿时间,老年代,标记清除算法。分为4个步骤:初始标记、并发标记、重新标记、并发清除。初始标记和重新标记需要stop the world。初始标记只是标记GCRoot直接关联的对象,非常快。并发标记是GCRoot的tracing过程。重新标记是为了修正并发标记期间,用户线程继续运行导致的变动,也很迅速。第一步和第三部都很快,所以用户线程停顿时间很短,这就是CMS的目的。它很优秀:并发、停顿短。但是也有缺点:
并发阶段和用户线程并行,会占用cpu资源,影响用户程序,总吞吐量降低。
并发期间程序会需要空间给新对象,所以不能等100%满了再开始回收。这个比例需要控制。太小导致浪费,太大可能会并发阶段不够了,而且用备用的SrialOld,等待时间很长。
因为是用的标记清除算法,会有碎片,如果无法找到足够的连续空间,会因为一次full gc。可以参数设置在要full gc时,合并整理。这个整理操作无法并发,因此停顿时间会变长。还有一个参数设置多少次的不整理的full gc后,跟随一次带整理的full gc。
G1收集器:
缩短stop the world时间
不用配合其他算法就能对整个堆管理,但可以用不同的方法管理不同的对象区域。
总体看是标记整理,局部看是复制算法。所以不会产生碎片。
与CMS相比,不知追求低停顿,同时建立可预测停顿时间的模型。
& & & & & G1将堆划分为多个相同大小的区域,新生代和老年代的概念仍被保留,但是只是一系列区域的集合而已。它将每个区域估算回收价值,在用户允许的停顿时间内,尽可能的回收价值高的区域。它的步骤和CMS非常类似:
& & & & & 但是回收阶段不是并发的,因为暂停用户线程能大幅提高回收效率。如果追求低停顿、可预测停顿,G1可以尝试。如果追求吞吐量,没有什么好处。
& & 开头数字式虚拟机运行时长,单位秒。中括号然后跟着本次gc类型:GC或Full GC。再中括号,跟着回收区域。然后是已使用内存-&回收后已使用内存(区域总内存)。然后跟着区域回收用时,单位秒。然后中括号外是堆的总内存情况和总用时。
常用参数:
内存分配策略:
在eden区分配内存,也是大多数情况
在老年代直接分配,因为分配担保机制。
新生代熬过了一定次数的Minor GC,年龄足够大的就进入老年代。默认年龄阀值为15,可配置。
并不是永远炒锅阀值才进入老年代。当新生代内同一年龄的对象大小总和超过了Survivor区的一半,年龄大于等于该年龄的对象,直接进入老年代。
分配担保:使用复制收集算法时,可能某次minor gc存活对象很多,survivor不足以承受,就需要老年代分配担保。所以在进行Minor GC前,虚拟机会检查老年代剩余空间是否大于新生代对象大小综合。如果大于则安全;如果小于,看参数设置是否允许冒险,如果允许冒险,会比较以往每次从新生代到老年代的对象大小的平均值和当前老年代的空余空间大小,如果剩余空间大,则允许此次Minor GC,如果剩余空间小或者不允许冒险,则Full GC。如果Minor后,老年代空间还是不够用,则还要FullGC。虽然如果冒险失败了,绕了很大很大的圈子,但是一般情况下,还是设置允许冒险,避免FullGC的频繁发生。这个开关是HandlePromotionFailure。
版权所有 IT知识库 CopyRight (C)
IT知识库 IT610.com , All Rights Reserved.Java_GC(绝对干货)
Java_GC(绝对干货)
浏览 636回答 1
codergroup
发错地方了,广告嫌疑
随时随地看视频JVM学习笔记(二)JVM垃圾回收机制 – 科网
今天记录并巩固下学到的JVM垃圾回收的相关知识,在JVM中,垃圾回收主要发生在堆中,在回收对象前JVM首先需要确认哪些对象是可回收的,一般判断对象是否应该回收有两种方式:
引用计数算法
顾名思义,引用计数算法其实就是计算某个对象的引用数。首先为每个对象添加一个引用计数器,当有一个地方引用了某一对象,则该计数器ij当某一地方不在引用时,则引用计数器Ģ引用计数算法很实用,且使用起来效率也很不错,但是无法解决对象间的循环引用从而导致每个对象的引用计数器都不–GC无法对对象进行回收。
可达性分析算法
目前JVM的主要使用的算法。该算法的核心就是通过可达性来作为判断对象是否可被回收的依据。通过一系列称为“GC-ROOT”的对象作为起点向下进行检索,检索的路径称为引用链,若某一对象对于所有引用链均不可达,则可判断该对象为可回收。在JAVA中,可作为GC-ROOT节点的为:
    1 虚拟机栈中引用的对象;
    2 方法区中类中静态属性引用的对象;
    3 方法区中常量引用的对象;
    4 本地方法栈中引用的对象。
JAVA中对引用进行了划分,使我们能够更好地管理对象以及内存,划分出的引用类型为强,软,弱,虚4中类型:
    1 强引用(Strong Reference):对于拥有强引用的对象,JVM在任何时候都不会回收
    2 软引用(Soft Reference):对于拥有软引用的对象,只有当JVM内存不足时才会被回收
    3 弱引用(Weak Reference):对于拥有弱引用的对象,无论内存是否够,JVM都会在下一个GC回收周期将该对象回收
    4 虚引用(Phantom Reference):对于拥有虚引用的对象,当该对象被回收时收到一个系统通知
当某一对象被判定“不可达”时,JVM不会立刻回收,而是会进行至少两次标记,在第一次标记之后进行筛选,筛选条件为是否可执行finalize()方法,若该对象没有覆盖finalize()方法或者finalize()方法已经被调用过,则JVM不会执行该方法。
在调用finalize()方法之后若该对象与任意GC-ROOT建立了联系,则不会被JVM回收,反之则被回收。注意:同一个对象finalize()方法只会被执行一次。
事实上虽然不是必须,但是方法区也是可以被垃圾回收的,回收的主要为两类:废弃常量与无用的类。常量的回收机制与对象相似,若某一在常量池的常量未被引用,则在必要到的情况下可被回收。而判断类是否无用则需要以
条件:
    1 在JAVA中不存在该类的实例;
    2 该类对应的ClassLoader已经被回收;
    3 该类对应的 java.lang.Class 对象不存在引用,无法在任何地方通过反射机制访问该类的方法。
当我们需要大量使用反射或者频繁自定义ClassLoader时,可以考虑对方法区进行垃圾回收。
Copyright 2013 - 2018 科网科技. All Rights Reserved

我要回帖

更多关于 c 引用计数 的文章

 

随机推荐