轻松get JVM——JVM垃圾回收算法

JVM中最重要的功能之一就是自动的垃圾回收机制了

JVM就像一个大工厂,要想掌控工厂,就必须了解JVM的种种设计

对象已死?

判断一个生命是否死亡似乎是简单的,但是内存中的对象可不是这么简单

怎样的对象才算死亡?这个问题大牛们似乎给出了合理的答案

当一个对象不存在指向它的引用,这个对象就可能判定为死亡。

JVM为了能够准确的判断对象的是否死亡,设计了种种算法,最主要的两种算法是

引用计数算法可达性分析算法

引用计数算法

引用计数法的原理很简单,给对象添加一个引用计数器,每次引用就加一,失效就减一

引用计数算法

问题:对象之间相互循环引用,则永远不可能为0

可达性分析算法

主流商用程序语言的主流实现中,都是通过可达性分析来判断对象是否存活

思路:通过一系列称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索搜索所走的路径称为引用链当一个对象到GC Roots没有任何引用链相连(不可达),则证明此对象不可用

可达性分析算法

GC Roots的对象包括:

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象

    栈帧中的本地变量表:

    栈帧对应一个Java方法,局部变量表存放方法参数方法内部定义的局部变量

  • 方法区中类静态属性引用的对象

  • 方法区中常量引用的对象

  • 本地方法栈中JHI(即一般说的Native方法) 引用的对象

总结为:线程栈帧中正在使用的对象,各种静态对象

另外一种对象

除去上面的生死,还有一种对象

“食之无味,弃之可惜”:当内存足够,我们希望能保留它。当内存不足时,我们可以抛弃这些对象。

Java对引用进行了细致的划分

  • 强引用

    在程序代码中普遍存在

    正常使用的new就是一种强引用

    强引用只要存在就不会回收被引用的对象

  • 软引用

    描述一些还有用并非必需的对象

    在系统将要发生内存溢出前,将会把这些对象列进垃圾回收的范畴。

    SoftReference类来实现

  • 弱引用

    描述非必需对象,强度弱于软引用

    弱引用关联的对象只能生存到下一次垃圾收集发生前

    WeakReference来实现

  • 虚引用

    幽灵引用或幻影引用。

    能在这个对象被垃圾收集器回收时收到一个系统通知

    PhantomReference实现

垃圾回收步骤

一次筛选

对象被可达性分析标记后,将筛选出来需要执行finalize()方法的对象,将这些对象放在名为F-Queue的队列之中。

稍后将有虚拟机自动建立的、低优先级Finalizer线程传递执行命令给该对象。

执行命令表示,虚拟机只负责摁下发射按钮,至于命中目标,虚拟机不会负责。

这样可以防止队列卡死或执行缓慢

二次筛选

虚拟机垃圾回收器小等一下队列,便会去检查这个队列若此时的对象找到了属于他的引用(可以把this赋值给某个变量),这个对象将“成功逃生”,GC将会把该对象移除即将回收的集合

回收方法区

方法区存放的是各种类信息,垃圾收集的效率远低于新生代。

主要为两部分内容:废弃常量和无用的类

废弃常量

如“abc”在没有使用的情况下,在必要的情况下,会被系统清理出常量池。

无用的类

  1. 该类所有的实例都已经被回收。
  2. 加载该类的ClassLoader已经被回收。
  3. 该类对应的java.lang.Class对象没有任何地方引用,无法在任何地方通过反射访问该类的方法。

满足上述3个条件,可以被回收,但并不一定被回收。

垃圾收集算法

标记-清除

步骤

  1. 标记所有需要回收的对象
  2. 标记完成后统一回收

不足

  1. 效率低。标记和清除两个过程效率都不高。
  2. 空间问题。标记清除后会产生大量不连续内存碎片。

images

复制

过程

某一块内存区域活着的对象整体复制到新的内存块,然后将已使用过的内存空间一次性清理掉

不足

  1. 方法简单高效,但内存区域缩小为原来的一半,太消耗资源。
  2. 在对象存活率较高时就要进行较多的复制操作,效率将变低。

IBM公司研究表明,新生代大多数对象“朝生夕死”,不需要按照1:1的比例划分,将内存分为一块较大的Eden空间和两块较小的Survivor空间。

回收时,Eden和Survivor中还活着的对象一次性地复制到另外一块Survivor空间上。最后清理Eden和刚才使用过的Survivor空间

HotSpot虚拟机默认大小比例为8:1

Survivor空间不够用时,需要依赖其他内存(老年代)进行分配担保

download

标记-整理

  1. 标记存活对象。
  2. 所有存活对象向一端移动。
  3. 清理掉端边界以外的内存。

垃圾收集算法——标记-整理算法(Mark-Compact)

分代收集

目前商业虚拟机都采用"分代收集"

根据对象的存活周期的不同将内存划分为几块。一般分为新生代和老年代。

根据各个年代的特点采用适当的收集算法。

猜你喜欢

转载自blog.csdn.net/weixin_44494373/article/details/107326545
今日推荐