• jvm--4垃圾收集



    6. 垃圾收集GC
    (1)当需要排查各种内存溢出,内存泄漏等问题,当GC成为系统达到更高性能的瓶颈时,我们就需要对这些自动化的GC进行监控和调节。

    (2)PC计数器、本地方法栈、虚拟机栈,随方法或者线程的结束而消亡,所以不用考虑回收其内存。内存回收的主要区域是 堆Heap 和 方法区。

    (3) 垃圾收集器,在回收对象前需要判断对象是否还存活,判断对象是否存活方法:

    a.引用计数算法: 给对象添加一个引用计数器,每当有一个地方引用它时,计数器值就+1;当引用失败时,计数器值就-1。
    任何时刻,计数器值为0的对象就是不可能被再使用的。
    优点:实现简单,效率高
    缺点:很难解决对象之间相互引用的问题。如GcBean里面的问题。(两个在堆上的对象相互引用,但是他们的句柄都指向了null,
    已经没有句柄指向他们,所以这两个对象不会再被用到,但是,因为他们之间相互引用,所以不会被垃圾回收。

    b.可达性分析算法(Reachability Analysis): 思路,通过一系列称为 "GC Roots"的对象,作为起始点,从这些节点开始向下
    搜索,搜索走过的路径称为引用链(Reference Chain),当一个对象到GC Roots 没有任何引用链时,则证明这个对象是不可用的。
    可以被垃圾收集器回收的。

    ----------------------------------------------------------
    | ---------- |
    | |GC Roots| |
    ----------------------------------------------------------
    |
    |
    --------- ----------
    | obj1 | | obj3 |
    --------- ----------
    | |
    | |
    --------- ----------
    | obj2 | | obj4 |
    --------- ----------

    如图obj1和obj2是可用对象,不会被GC回收;
    obj3和obj4虽然他们之间有联系,但是,他们到GC Roots 不可达,所以,他们将会判定为不可回收对象。

    c.在java中可作为GC Roots的对象的有:
    I.虚拟机栈中引用的对象。
    II.方法区中类静态属性引用的值。
    III.方法区中常量引用的对象
    IV.本地方法栈中 JNI(即一般说的native方法) 引用的对象。

    (4)回收堆
    I. 对象在经过可达性分析后,发现没有与GC Roots相关联的引用链,它将会被第一次标记(标记此对象没有引用链),并且进行一次筛选,此对象是否有必要执行finalize()方法。
    II. 筛选的条件是: 此对象是否有必要执行finalize()方法,
    当对象没有覆盖finalize()方法,或者对象的finalize()方法被虚拟机掉用过,虚拟机将这两种情况都视为,没有必要执行。
    III. 如果对象被虚拟机判定有必要执行finalize()方法时,那么对象会被放置在一个叫做F-QUEUE的队列当中,稍后会有一个虚拟机
    建立的,优先级低的Finalizer线程去执行它。
    IV. finalize()方法,是对象逃脱被回收的最后一次机会,如果对象在finalize方法中重新与GC Roots上的任何一个对象关联上,
    那么GC在第二次标记时,将把这个对象移除“即将回收集合”;如果对象这是还没有逃脱,那它就基本被回收了。
    V. 需要注意一点,每个对象的finalize()方法只会被JVM执行一次,如果对象通过finalize()方法逃出过被回收一次,那么就不会
    有第二次。
    finalize()应尽量避免使用,运行代价高昂,不确定性大,无法保证各个对象的调用顺序。
    (5)回收方法区
    永久代的垃圾收集主要回收两部分内容:废弃常量和无用的类。
    I.常量池中有(类、接口、方法、字段的符号引用,字符),判断一个常量是否是废弃常量比较简单,有没有对象引用常量,如果没有其他地方引用
    了这个常量,如果这是发生内存回收,而且必要的话,这个常量就会被回收。
    II.无用的类:
    a. 加载类的ClassLoader已经被回收
    b. 该类的所有实例都已经被回收,即java堆中不存在该类的任何实例。
    c.无法在任何地方通过反射访问该类。
    满足这三个条件,类就可以被回收。Hotspot虚拟机,提供, -Xnoclassgc 参数控制。

    (6)垃圾收集算法
    I. 标记-清除(Mark-Sweep)算法:
    a.标记出所有需要被回收的对象
    b.标记完成后,统一回收被标记的对象。
    缺点: 效率问题,标记和清除两个过程效率都不高。
    空间问题,标记清除之后会产生大量不连续的内存碎片,可能会导致以后要分配大内存对象时,无法找到足够的连续内存,而不得不
    触发另一次垃圾收集动作。

    II. 复制(Copying)算法:HotSpot虚拟机
    a. 将用内存按容量划分为大小相等的两块,每次只使用其中的一块,当这一块内存用完了,就将还存活的对象复制到另外一块内存,然后把
    使用过的空间,一次性清除掉。
    优点:实现简单,运行高效
    缺点: 内存缩小成原来的一般,影响性能。

    b. 新生代中的对象98%是 朝生夕死,所以不需要按照1:1的比例来划分内存空间。而是将 新生代内存 分为一块较大的Eden空间和两块较小的Suvivor空间,
    每次使用Eden和其中一块的Survivor;
    当回收时,将Eden区和Survivoe区的存活对象,一次性复制到另外一块Survivor区,清理Eden区,和刚才用过的Survivor空间。
    Eden区和Survivor区占比:Eden:S1:S2 = 8:1:1 , 即每次新生代中可用内存空间为整个内存空间的 (1+8 ):1 = 90% ,
    c.如果Survivor区空间不够用时,需要依赖 老年代 进行分配担保机制,把对象分配到老年代。

    III. 标记-整理 算法:
    a.标记出所有需要被回收的对象
    b.标记完成后,让所有的存活对象向一端移动,然后清理掉边界意外的内存区域。

    IV. 分代收集(Generation Collection) 算法
    分代收集没有新东西,根据对象存活周期不同,把对象分为几部分。

    a. 把java堆分为老年代和新生代,新生代使用复制算法(Eden , Suvivor1 , Suvivor2 ),
    b.老年代因为对象存活率高,没有更多的内存使用复制算法收集,所以,使用 标记-清除,或者使用 标记-整理算法 进行垃圾回收。
    (7) 垃圾收集器
    I.http://blogs.sun.com
    Serial ParNew CMS Serial Old GI ..

    (8) Full GC 和 Minor GC
    I.新生代GC ,Minor GC ,指发生在新生代的垃圾收集动作,因为java对象大多都是朝生夕死,所以Monor GC非常频繁,一般回收速度也比较快。
    II.老年代GC ,FULL GC ,发生在老年代的GC ,一般比新生代GC慢十倍以上。

    (9) 内存分配策略:
    I.对象优先在Eden区分配。
    II.大对象直接进入老年代(很长的字符串,或者数组byte[]),老年代垃圾回收比较慢,所以应尽量少使用大对象(还有短大对象)。
    -XX:PretenureSizeThreshold ,参数,大于此参数值的对象进入老年代。
    III.长期存活的对象进入老年代。

  • 相关阅读:
    今天遇到的报错Babel noteThe code generator has deoptimised the styling of ...as it exceeds the max of 500KB.
    轻松理解Promise.all 、Promise.then、Promise.race有什么区别以及使用方法
    JS循环类数组对象,获得页面所有的某个ClssaName,处理它的属性
    Angular在用户登录后设置授权请求头headers.append('Authorization', 'token');
    webpack配置less以及js中引入的图片问题
    超级容易理解的Three.js中的物体rotation
    新下载了一个框架,然后npm install时候报错npm ERR! Maximum call stack size exceeded
    webpack打包后发现有一部分代码还携带注释,如何解决?/webpack打包删除注释以及console.log--快快点进来看一看吧~~
    composer 下载扩展包
    postman 模拟登录状态
  • 原文地址:https://www.cnblogs.com/fubaizhaizhuren/p/5938484.html
Copyright © 2020-2023  润新知