JVM判断对象是否存活

栏目: Java · 发布时间: 6年前

内容简介:给对象中添加一个引用计数器,每当又一个地方引用它时,计数器值加1;当引用失效时,计数器减1;任何时刻计数器都为0的对象就是不可能在被使用的.但是Java语言中没有选用引用计数法来管理内存,其中最主要的原因是它很难解决对象之间相互循环依赖的问题.例如: 在testGC中,对象objA和对象objB都有字段instance,赋值objA.instance=objB.instance及objB.instance=objA.instance,除此之外这两个对象再无其他任何引用,实际上这两个对象都已经不能再被访问,但

给对象中添加一个引用计数器,每当又一个地方引用它时,计数器值加1;当引用失效时,计数器减1;任何时刻计数器都为0的对象就是不可能在被使用的.但是 Java 语言中没有选用引用计数法来管理内存,其中最主要的原因是它很难解决对象之间相互循环依赖的问题.

例如: 在testGC中,对象objA和对象objB都有字段instance,赋值objA.instance=objB.instance及objB.instance=objA.instance,除此之外这两个对象再无其他任何引用,实际上这两个对象都已经不能再被访问,但是他们因为他们互相引用着对方,他们的引用计数都不为0,于是引用计数算法无法通知GC收集器回收它们. 打印GC详细信息: -XX:+PrintGCDetails

public class ReferenceCountingGC {

    public Object instance = null;

    public static void main(String[] args) {
        ReferenceCountingGC objA = new ReferenceCountingGC();
        ReferenceCountingGC objB = new ReferenceCountingGC();
        objA.instance = objB;
        objB.instance = objA;


        objA = null;
        objB = null;

        //假设在这行发生了gc,objA和objB是否被回收
        System.gc();
    }
}
复制代码

GC日志为:

[GC (System.gc()) [PSYoungGen: 334480K->4736K(334848K)] 597914K->270331K(1017536K), 0.0019879 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] 
[Full GC (System.gc()) [PSYoungGen: 2408K->0K(298688K)] [ParOldGen: 0K->3363K(682688K)] 3408K->3363K(981376K), [Metaspace: 3162K->3162K(1056768K)], 0.0050515 secs] [Times: user=0.02 sys=0.00, real=0.00 secs] 
Heap
 PSYoungGen      total 153088K, used 3947K [0x0000000715580000, 0x0000000720000000, 0x00000007c0000000)
  eden space 131584K, 3% used [0x0000000715580000,0x000000071595afc0,0x000000071d600000)
  from space 21504K, 0% used [0x000000071d600000,0x000000071d600000,0x000000071eb00000)
  to   space 21504K, 0% used [0x000000071eb00000,0x000000071eb00000,0x0000000720000000)
 ParOldGen       total 349696K, used 872K [0x00000005c0000000, 0x00000005d5580000, 0x0000000715580000)
  object space 349696K, 0% used [0x00000005c0000000,0x00000005c00da3b8,0x00000005d5580000)
 Metaspace       used 3169K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 346K, capacity 388K, committed 512K, reserved 1048576K
复制代码

GC日志分析:

GC (minor )日志:

JVM判断对象是否存活

Full GC 日志:

JVM判断对象是否存活

后半段分析

JVM判断对象是否存活

对照上面的图,GC日志中的PSYoungGen(PS是指Parallel Scavenge)为Eden+FromSpace,而整个YoungGeneration为Eden+FromSpace+ToSpace。

我们设置的新生代大小为10240K,这包括9216K大小的PSYoungGen和1024K大小的ToSpace。其中,PSYoungGen中的Eden:FromSpace为8:1,

这包括8192K的Eden和1024K的FromSpace。

详细日志输出:

参数设置为:

-XX:+PrintGCDetails -XX:-UseAdaptiveSizePolicy -XX:SurvivorRatio=8 -XX:NewSize=10M -XX:MaxNewSize=10M

参数解释:

-XX:+PrintGCDetails 启用日志

-XX:-UseAdaptiveSizePolicy 禁用动态调整,使SurvivorRatio可以起作用

-XX:SurvivorRatio=8 设置Eden:Survivior=8

-XX:NewSize=10M -XX:MaxNewSize=10M 设置整个新生代的大小为10M

默认垃圾收集器为:Parallel Scavenge

在运行日志结果中我们可以看到GC日志包含“2408K->0k”,老年代从2408K(约2M,其实就是objA与objB)变为了512K,意味着虚拟机并没有因为这两个对象互相引用就不回收它们,这也证明虚拟机并不是通过引用计数法判断对象是否存活的.可以看到对象进入了老年代,但是大家知道,对象刚创建的时候是分配到新生代中到,要进入老年代需要到new ObjA才行,但是这里objA和objB却进入了老年代.这是因为Java堆区会动态增长,刚开始时堆区较小,对象进入老年代还有一些规则,当survior空间中同一代的对象大小之和超过survior空间的一半时,对象将直接进入老年代.

二、可达性分析算法(GC Roots Analysis):主流用这个判断

这个算法的基本思路是通过一系列名为“GC Root”的对象作为起点,从这些节点开始往下搜索,搜索走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用到,下图对象object5,object6,object7虽然有互相判断,但它们到GC Roots是不可达到,所以它们将会判定为可回收对象

JVM判断对象是否存活

在Java语言里,可作为GC Roots对象的包括如下几种:

  • 1、虚拟机栈(栈桢中的本地变量表)中的引用的对象
  • 2、方法区中的类静态属性引用的对象
  • 3、方法区中的常量引用的对象
  • 4、本地方法栈中JNI的引用的对象

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Music Recommendation and Discovery

Music Recommendation and Discovery

Òscar Celma / Springer / 2010-9-7 / USD 49.95

With so much more music available these days, traditional ways of finding music have diminished. Today radio shows are often programmed by large corporations that create playlists drawn from a limited......一起来看看 《Music Recommendation and Discovery》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

SHA 加密
SHA 加密

SHA 加密工具