【Java】の基础——JVM垃圾回收

来源:互联网 发布:执行偏差算法 is 编辑:程序博客网 时间:2024/06/05 17:38

  • 垃圾收集
    • 一Java堆的垃圾回收
      • 确定对象是否死亡的方法
        • 计数算法
        • 可达性分析算法
      • 引用
      • finalize方法
    • 二方法区的垃圾回收
    • 三垃圾收集算法
      • 1标记-清除算法
      • 2复制算法
      • 3标记-整理算法
      • 4分代收集算法
    • 内存分配
      • 对象在Eden中分配
      • 大对象直接进入老年代
      • 长期存活的对象直接进入老年代
      • 动态对象年龄判定
      • 空间分配担保

Java内存管理最终可以归结为自动化的解决了两个问题:给对象分配内存以及回收分配给对象的内存

垃圾收集

一、Java堆的垃圾回收

确定对象是否“死亡”的方法

我们要回收掉那些不可能再被任何途径使用到的对象。那么如何判断呢?

计数算法

给对象添加一个引用计数器,每当引用它,计数器加1;引用失效时,计数器减1。计数器为0的对象就不可能再被使用。
它的缺点是很难决对象之间相互循环引用的问题

可达性分析算法

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

Java中的GC Roots包括下面几种·虚拟机栈(栈帧中的本地变量表)引用的对象。·方法区中类静态属性引用的对象。·方法区中常量引用的对象。·本地方法栈中JNI(即Native方法)引用的对象。

引用

Java将引用分为强引用软引用弱引用虚引用四种,四种引用的强度依次减弱。
- 强引用:永远不会回收。
- 软引用:在系统将要发生内存溢出异常之前,回收,然后如果这次回收之后还没有足够的内存,才会抛出内存溢出异常。软引用使用SoftReference实现软引用。
- 弱引用:垃圾收集器工作时,无论当前内存是否足够,都会回收。弱使用WeakReference实现。
- 虚引用:一个对象是否有虚引用存在没有影响。唯一目的就是能在这个对象被收集器回收时收到一个系统通知。虚引用使用PhantomReference实现。

finalize()方法

真正宣告一个对象“死亡”要进行两次标记过程:如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链,那它将会被第一次标记并进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。
当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,这两种情况都属于“没有必要执行”。
如果这个对象判定为“有必要执行”,会放置在F-Queue队列中,并在稍后由一个虚拟机自动建立的、低优先级的Finalizer线程去执行。
如果对象要在finalize()中拯救自己,只要重新与引用链上的某个对象关联即可,之后他会在第二次标记时被移出“即将回收”的集合;否则就会被回收。

二、方法区的垃圾回收

Java虚拟机可以不要求在方法区实现垃圾收集,而且方法区的垃圾回收效率很低。
永久代的垃圾收集主要回收两部分内容:废弃常量无用的类
- 回收废弃常量和回收Java堆中的对象类似。
- “无用的类”进行判断比较复杂:
1. 该类的所有实例都被回收。
2. 加载该类的ClassLoader已被回收。
3. 该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
同时 满足以上四个条件才可以进行回收(不是必须)。

三、垃圾收集算法

1、标记-清除算法

首先标记处所有需要回收的对象,在标记完成后统一回收这些对象。
这个算法效率不高而且浪费空间。

2、复制算法

将内存分为两个空间: 一块较大的Eden空间两块较小的Survivor空间。分配空间时,使用Eden和其中一块Survivor空间。在回收的时候将Eden和Survivor中还存活的对象一次性的复制到一块Survivor空间上,再清理掉Eden和刚才用过的Survivor空间。

3、标记-整理算法

让所有存活的对象都向一端移动,然后直接清理掉边界以外的内存。

4、分代收集算法

把Java堆分为新生代老年代
新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法
老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记-清理”或“标记-整理”算法来进行回收。

内存分配

对象在Eden中分配

大多数情况下对象在新生代Eden区中分配。当Eden区没有足够的空间进行分配时,虚拟机发起一次 Minor GC

新生代GC(Minor GC):指发生在新生代的垃圾收集,比较频繁,速度较快。老年代GC(Major GC/Full GC):指发生在老年代的GC。速度要比Minor GC慢十倍以上。

大对象直接进入老年代

需要大量连续内存空间的对象(比如很长的字符串及数组),直接进入老年代。

长期存活的对象直接进入老年代

如果对象在Eden出生并经过第一次Minor GC后仍然存货,并且能被Survivor容纳的话,将被移动到Survivor空间中,并且对象年龄设为1
对象在Survivor区每经过一次Minor GC 年龄增加1岁
当他的年龄增加到一定程度(默认15岁),就会晋升到老年代中。

动态对象年龄判定

如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代

空间分配担保

在Minor GC之前,虚拟机会先检查老年代最大可用的连续空间是否大于新生代所有对象总空间。

1. 是——Minor GC是安全的。2. 否——虚拟机查看HandlePromotionFailure是否允许担保失败:    2.1. 不允许——进行Full GC。    2.2. 允许——检查老年代最大可用连续空间是否大于历次晋升到老年代对象的平均大小:        2.2.1. 大于——尝试着进行Minor GC(有风险)。        2.2.2. 小于——进行Full GC。
0 0
原创粉丝点击