JVM系统自学笔记4--判断垃圾、五种引用

一、判断垃圾

1、引用计数法

如果两个对象互相引用,计数器都为1,即使他们都没有被使用,都不会被清理。

2、可达性分析算法(jvm使用的)

Java虚拟机中的垃圾回收器采用可达性分析来探索所有的对象

扫描堆中的对象,判断是否能根据GC Root的引用链找到该对象,找不到则回收

二、五种引用

1、强引用:指向某一对象的所有强引用都断开,该对象才能被回收。

2、软引用:如果垃圾回收之后,内存依然不足,只被软引用的对象会被回收。

3、弱引用:只要发生垃圾回收,只被弱引用的对象就会被回收。

4、虚引用

      虚引用的ByteBuffer,没有被强引用,被回收掉,分配的直接内存尚未回收

      虚引用进入引用队列中,anRefferenceHandler在队列中寻找到虚引用Cleer

      调用Unsafe.freeMemory()方法释放直接内存;

      释放引用。

5、终结器引用

终结器对象引用的对象没有被强引用,在被回收前,终结器引用转移到引用队列,一个优先级较低的线程finallize在引用队列中寻找终结器引用;

并找到终结器引用的对象,调用finalize()方法;

下次垃圾回收时,回收该对象。

五种引用举例

强引用:一般平常代码中大部分引用都是强引用

-Xmx20m
 	List<byte[]> list1 = new ArrayList<>();
        for (int i = 0;i < 5;i++){
            list1.add(new byte[_4MB]);
        }

+++++++++++++打印结果++++++++++++++
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at com.example.jvm.GC.softY.main(softY.java:12)

++++++++++++++++解释+++++++++++++++++++
-Xmx20m将堆内存最大设置为20m,强引用byte数组无法被回收,25m>20m,所以堆内存溢出。

软引用

-Xmx20m -XX:+PrintGCDetails -verbose:gc

public static  void soft(){
        List<SoftReference<byte[]>> list = new ArrayList<>();
        for (int i = 0;i < 5;i++){
            SoftReference<byte[]> ref = new SoftReference<>(new byte[_4MB]);
            System.out.println(ref.get());
            list.add(ref);
            System.out.println(list.size());
        }
        System.out.println("循环结束,"+ list.size());
        for (SoftReference<byte[]> ref:list){
            System.out.println(ref.get());
        }
    }

++++++打印结果++++++
[B@3fee733d
1
[B@5acf9800
2
[B@4617c264
3
++++++++++
[GC (Allocation Failure) [PSYoungGen: 1953K->496K(6144K)] 14241K->13133K(19968K), 0.0013159 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[B@36baf30c
4
[GC (Allocation Failure) --[PSYoungGen: 4817K->4817K(6144K)] 17455K->17455K(19968K), 0.0008319 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Ergonomics) [PSYoungGen: 4817K->4488K(6144K)] 
[ParOldGen: 12637K->12550K(13824K)] 17455K->17038K(19968K),
 [Metaspace: 3085K->3085K(1056768K)], 0.0054989 secs]
 [Times: user=0.00 sys=0.00, real=0.01 secs] 
[GC (Allocation Failure) --[PSYoungGen: 4488K->4488K(6144K)] 
17038K->17038K(19968K), 0.0009131 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [PSYoungGen: 4488K->0K(6144K)] 
[ParOldGen: 12550K->637K(8704K)] 17038K->637K(14848K), 
[Metaspace: 3085K->3085K(1056768K)], 0.0076801 secs]
 [Times: user=0.02 sys=0.00, real=0.01 secs] 
[B@7a81197d
5
++++++++++++++++++++++
GC日志可以看出,Eden区内存不足触发的 minor GC只是将新生代对象转移到老年代,并没有回收。
在老年代内存不足时,触发FULL GC ,但是第一次触发并未回收,直到第二次触发再回收所有软引用对象。
++++++++++++++++
循环结束,5
null
null
null
null
[B@7a81197d
Heap
 PSYoungGen      total 6144K, used 4433K [0x00000000ff980000, 0x0000000100000000, 0x0000000100000000)
  eden space 5632K, 78% used [0x00000000ff980000,0x00000000ffdd4500,0x00000000fff00000)
  from space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
  to   space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
 ParOldGen       total 8704K, used 637K [0x00000000fec00000, 0x00000000ff480000, 0x00000000ff980000)
  object space 8704K, 7% used [0x00000000fec00000,0x00000000fec9f660,0x00000000ff480000)
 Metaspace       used 3130K, capacity 4500K, committed 4864K, reserved 1056768K
  class space    used 341K, capacity 388K, committed 512K, reserved 1048576K

软引用配合引用队列
上述为配合引用队列的做法,虽然对象被回收,但是软引用没有被回收,因为最后输出了四个NULL,软引用还在。

 public static  void soft(){
        List<SoftReference<byte[]>> list = new ArrayList<>();
        //引用队列
        ReferenceQueue<byte[]> queue = new ReferenceQueue<>();

        for (int i = 0;i < 5;i++){
            SoftReference<byte[]> ref = new SoftReference<>(new byte[_4MB],queue);
            System.out.println(ref.get());
            list.add(ref);
            System.out.println(list.size());
        }
        Reference<? extends byte[]> poll = queue.poll();
        while(poll !=null){
            list.remove(poll);
            poll = queue.poll();
        }
        System.out.println("循环结束,"+ list.size());
        for (SoftReference<byte[]> ref:list){
            System.out.println(ref.get());
        }
    }
++++运行结果++++
1
[B@5acf9800
2
[B@4617c264
3
[B@36baf30c
4
[B@7a81197d
5
循环结束,1
[B@7a81197d
++++++软引用被清除 NULL消失++++++

弱引用

  public static  void weak(){
        List<WeakReference<byte[]>> list = new ArrayList<>();
        for (int i = 0;i < 10;i++){
            WeakReference<byte[]> ref = new WeakReference<>(new byte[_4MB]);
            list.add(ref);
            for (WeakReference<byte[]> ref1:list){
                System.out.print(ref1.get()+" ");
            }
            System.out.println();
        }
    }
++++打印结果+++
[B@3fee733d 
[B@3fee733d [B@5acf9800 
[B@3fee733d [B@5acf9800 [B@4617c264 
[GC (Allocation Failure) [PSYoungGen: 1953K->488K(6144K)] 14241K->13069K(19968K), 0.0006807 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[B@3fee733d [B@5acf9800 [B@4617c264 [B@36baf30c 
[GC (Allocation Failure) [PSYoungGen: 4809K->488K(6144K)] 17391K->13085K(19968K), 0.0005917 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[B@3fee733d [B@5acf9800 [B@4617c264 null [B@7a81197d 
[GC (Allocation Failure) [PSYoungGen: 4751K->488K(6144K)] 17349K->13125K(19968K), 0.0004115 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[B@3fee733d [B@5acf9800 [B@4617c264 null null [B@5ca881b5 
[GC (Allocation Failure) [PSYoungGen: 4731K->488K(6144K)] 17369K->13133K(19968K), 0.0004320 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[B@3fee733d [B@5acf9800 [B@4617c264 null null null [B@24d46ca6 
[GC (Allocation Failure) [PSYoungGen: 4718K->504K(6144K)] 17363K->13157K(19968K), 0.0003284 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[B@3fee733d [B@5acf9800 [B@4617c264 null null null null [B@4517d9a3 
[GC (Allocation Failure) [PSYoungGen: 4725K->488K(5120K)] 17379K->13173K(18944K), 0.0003207 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[B@3fee733d [B@5acf9800 [B@4617c264 null null null null null [B@372f7a8d 
[GC (Allocation Failure) [PSYoungGen: 4690K->160K(5632K)] 17376K->13276K(19456K), 0.0003747 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Ergonomics) [PSYoungGen: 160K->0K(5632K)] [ParOldGen: 13116K->714K(8192K)] 13276K->714K(13824K), [Metaspace: 3159K->3159K(1056768K)], 0.0045601 secs] [Times: user=0.02 sys=0.00, real=0.00 secs] 
null null null null null null null null null [B@2f92e0f4 

+++++++++++++++结论++++++++++++++++
弱引用对象在首次触发minor GC时,将弱引用对象转移到老年代中,再次触发 minor GC时,回收在Eden中的新生对象。
因为软引用占用内存,在没有及时回收引用时,老年代内存逐渐被软引用占用,直到内存不足,触发FULL GC ,回收所有的弱引用对象。
+++++++++++++++问题++++++++++++++++++
这样弱引用未被回收,还是会一直占用内存,所以还是需要配合引用队列回收弱引用,具体操作参考软引用。
发布了171 篇原创文章 · 获赞 5 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/QilanAllen/article/details/105623853