zoukankan      html  css  js  c++  java
  • 2.JAVA垃圾回收机制

    前言

    线程独享的内存区域有程序计数器,虚拟机栈,本地方法栈,这些区域不用考虑内存回收的问题,随着线程的执行结束,自然就回收了,而堆内存和方法区的回收则不一样,他们的内存分配和回收是动态的。

    1.对象存活与否

    • 法一:引用计数算法
    • 原理:每当有地方引用该对象时,计数器加一,当引用实效的时候,计数器减一,当计数器值为0的时候可以进行对象的内存回收。
    • 问题:无法解决对象之间的循环引用
    • 法二:可达性分析
    • 原理 :1.选择一系列的对象作为GC Roots(GC ROOTS:栈帧中的局部变量表中的对象引用,方法区中静态属性引用,常量池中的常量引用),其实我觉得除了object5=null这种情况之外都可以作为GC ROOTs
    •          2.如果对象之间存在引用关系,那么它们之间就应该可达,eg:Object1于Object2
    •          3.从GC ROOTs进行可达性分析如果不可达那么久认为对象可以被回收(eg:object5,object6,object7)
    • 图1.可达性分析算

    2.对象的垃圾回收过程---对象的二次标记过程(回收堆内存)

    • 1.进行可达性分析,发现对象不可达,则进行第一次标记
    • 2.第一次标记后的对象将会检查对象是否有覆盖finalize方法以及finalized()是否被执行过。
    • 3.finalized()函数没有被执行过的对象会被放入F-Queue队列中,执行finalized()函数,若执行过程中对象被重新引用,那么在第二次标记时该对象将会被移出F-Queue,否则对象会被回收。

    3.回收方法区(加载过的类、常量池、静态变量)

    • 回收对象:1.没用的类 2.无用常量
    • 什么样的类才是没用的类?
    • 无用常量:没有被引用的常量
    • 无用类:
    • 1.该类的所有实例已经被回收
    • 2.类的加载器已经被回收(CLASSLOAD)
    • 3.该类的CLASS对象没有被使用

    4.垃圾回收算法

    • 总体思想:标记---清除算法
    • 阶段一:对需要回收内存的对象进行标记
    • 阶段二:对标记过的内存进行回收
    • 问题:
    • 1.效率低下
    • 2.产生大量的内存碎片

    图2:标记-清除算法

    •  新生代对象的回收算法
    • 复制法
    • 1.新生代对象需要回收的对象数量比较少
    • 2.为了解决标记-清除算法效率低下的问题,我们把内存分为两部分,Eden和两块Survivor(8:1:1),Eden内存用完,进行垃圾回收之前,会把Eden上的存活的对象复制到survivor上,之后对Eden进行整块回收

    图3.复制法回收新生期内存

    • 老年代对象回收算法
    • 标记-整理
    • 老年代的对象存活时间比较旧,甚至会出现100%存活的极端情况,因此复制法不再适用。
    • 阶段一:标记
    • 阶段二:整理,先不对内存进行回收,而是把存活的对象向内存的一端进行移动,然后直接清除掉边界以外的内存。

    4.何时进行垃圾回收

    • safepoint
    • 为了避免程序长时间执行,往往会在代码复用较多的地方设置safepoint,例如方法跳转,循环跳转,异常跳转
    • 进行垃圾回收之前需要所有的线程在safepoint停下来,为了达到同步有两种方式
    • 1.抢先试:先中断所有的线程,然后让线程,自己“跑”到最近的safepoint
    • 2.主动式:在safepoint处设置一个轮训标志,当线程发现标志设置为true时,就会在轮询的位置停下来
    • safeRegion
    • 当线程分配不到CPU时间片的时候,线程自然就不能跑到safepoint,这时就要以来saferegion进行垃圾回收
    • saferegion是指在一片代码中对象的引用关系不发生变化的时候。

    5.垃圾回收器

    • 目前常见的垃圾回收器如图所示

    图4.虚拟机的垃圾回收器                

    • 简单介绍
    • 1.Serial
    • 新生期对象的单线程收集器,需要首先停止用户线程(stop the world)
    • 2.Serial Old
    • 老年期单线程,也需要停止用户线程
    • 3.ParNew
    • 新生期对象的多线程内存收集器
    • 4.Parallel Scavenge
    • 与Serial回收器类似是新生对象的垃圾回收器,Serial追求的是是的垃圾回收所占用的CPU时间尽量的短,而Parallel Scavenge追求的是最大吞吐量  (运行用户程序时间)/(运行用户程序时间+垃圾回收的时间)
    • 6.Parallel Old
    • Parallel Scavenge的老年版本
    • 5.CMS
    • 基于标记-清除的老年代垃圾回收器,分为如下四个步骤
        • 初始标记--GC Roots直接关联的对象
        • 并发标记--GC Roots Tracing的过程(与用户程序并发)
        • 重新标记--并发标记过程中,用户程序新长生的对象进行标记
        • 并发清理--进行垃圾回收(与用户程序并发)
    • 7.GI
    • 与CMS类似,并发清理变为筛选回收,加快回收的效率,还没有成熟版本
  • 相关阅读:
    POJ 3261 Milk Patterns (求可重叠的k次最长重复子串)
    UVaLive 5031 Graph and Queries (Treap)
    Uva 11996 Jewel Magic (Splay)
    HYSBZ
    POJ 3580 SuperMemo (Splay 区间更新、翻转、循环右移,插入,删除,查询)
    HDU 1890 Robotic Sort (Splay 区间翻转)
    【转】ACM中java的使用
    HDU 4267 A Simple Problem with Integers (树状数组)
    POJ 1195 Mobile phones (二维树状数组)
    HDU 4417 Super Mario (树状数组/线段树)
  • 原文地址:https://www.cnblogs.com/yangyunnb/p/6384047.html
Copyright © 2011-2022 走看看