JDK解构 - Java中的引用和动态代理的实现

咱们知道,动态代理(这里指JDK的动态代理)与静态代理的区别在于,其真实的代理类是动态生成的。但具体是怎么生成,生成的代理类包含了哪些内容,以什么形式存在,它为何必定要以接口为基础?javascript

若是去看动态代理的源代码(java.lang.reflect.Proxy),会发现其原理很简单(真正二进制类文件的生成是在本地方法中完成,源代码中没有),但其中用到了一个缓冲类java.lang.reflect.WeakCache<ClassLoader, Class<?>[], Class<?>>,这个类用到了弱引用来构建。java

在JDK的3个特殊引用中,弱引用是使用范围最广的,它的特性也最清晰,相对而言,其余两种逻辑稍显晦涩,源码中的注释也语焉不详。本文将简单介绍几种引用的行为特征,而后分析一下弱引用的一些实际应用场景,其中包含了动态代理中的实现。本文将包含如下内容:ios

  1. JDK中的引用类型
  2. 不一样引用类型对GC行为的影响
  3. 引用类型的实现
  4. ThreadLocal对弱引用的使用
  5. 动态代理对弱引用的实现
  6. 虚引用如何致使内存泄漏

JDK中「引用(Reference)」的类型

Java的全部运行逻辑都是基于引用的,其形态相似于不可变的指针,因此在Java中会有一些很绕的概念,好比说, Java中函数的传参是值传递,但这里所说的值,实际上是引用的值,因此你能够经过一个函数的参数来修改其对象的值。另外一方面,Java中还存在一些基本数据类型,它们没有引用,传递的是真实的值,因此不能在函数内部修改参数的值。npm

关于引用,Java中有这样几种:api

1. 强引用

全部对象的引用默认为强引用,普通代码中,赋值语句之间传递的都是强引用,若是一个对象能够被某个线程(活着的,下同)经过强引用访问到,则称之为强可达的(Strongly Reachable)。浏览器

强可达的对象不会被GC回收。缓存

2. 软引用(SoftReference

当一个对象不是强可达的,但能够被某个线程经过软引用访问到,则称之为软可达的(Softly Reachable)。app

软可达的对象的引用只有在内存不足时会被清除,使之能够被GC回收。在这一点上,JVM是不保证具体何时清除软引用,但能够保证在OOM以前会清除软可达的对象。同时,JVM也不保证软可达的对象的回收顺序,但Oracle JDK的文档中提到,最近建立和最近使用的软可达对象每每会最后被回收,与LRU相似。dom

3. 弱引用(WeakReference

当一个对象不是强可达的,也不是软可达的,但能够被某个线程经过弱引用访问到,则称之为弱可达的(Weakly Reachable)。jvm

弱引用是除了强引用以外,使用最普遍的引用类型,它的特性也更简单,当一个对象是弱可达时,JVM就会清除这个对象上的弱引用,随后对这个对象进行回收动做。

4. 虚引用(PhantomReference

当一个对象,经过以上几种可达性分析都不可达,且已经finalized,但有虚引用指向它,则它是虚可达的(Phantom Reachable)。

虚引用是行为最诡异,使用方法最难的引用,后边会讲到。

虚引用不会影响GC,它的get()方法永远返回null,惟一的用处就是在GC finalize一个对象以后,它会被放到指定的队列中去。关于这个队列会在下边说明。

不一样GC行为背后的原理

JVM GC的可达性分析

JVM的GC经过可达性分析来判断一个对象是否可被回收,其基本思路就是以GC Roots为起点遍历链路上全部对象,当一个对象和GC Roots之间没有任何的直接或间接引用相连时,就称之为不可达对象,则证实此对象是不可用的。

而进一步,Java中又定义了如上所述的4种不一样的可达性,用来实现更精细的GC策略。

Finalaze和ReferenceQueue

对于普通的强引用对象,若是其变成不可达以后,一般GC会进行Finalize(Finalize主要目的是让用户能够自定义释放资源的过程,一般是释放本地方法中使用的资源),而后将它的对象销毁回收,但对于本文中讨论的3种引用,还有可能在这个过程当中作一些别的事情:

  1. GC根据约定的规则来决定是否清除这些引用

    这方面上一节已经讲过了,每一个引用类型都有约定的处理规则。

  2. 若是它们注册了引用队列,在Finalize对象后,将引用的对象放入队列。

    主要用来使开发者能够获得对象被销毁的通知,固然,如虚引用这样的,其引用不会自动被清除,因此它能够阻止其所引用的对象被回收。

引用(java.lang.ref.Reference<T>)对象的状态

这里所说的「引用对象」指的是由类java.lang.ref.Reference<T>生产的对象,这个对象上保持了「须要特殊处理的」对「目标对象」的引用。

引用对象有4种状态,根据它与其注册的队列的关系,分为如下4种:

  1. Active
    引用对象的初始状态,表示GC要按照特殊的逻辑来处理这个对象,大体方法就是按照上一节提到的。

  2. Pending
    若是一个引用对象,其注册了队列,在入队以前,会进入这个状态。

  3. Enqueued

    一个引用对象入队后,进入这个状态。

  4. Inactive

一个引用对象出队后,或者没有注册队列,其队列是一个特殊的对象java.lang.ref.ReferenceQueue.NULL,表示这个对象已经没有用了。

几种引用的实际应用

平常开发工做中,用到除强引用以外的引用的可能性很小,只有在处理一些性能敏感的逻辑时,才须要考虑使用这些特殊的引用,下面就举几个相关的实际例子,分析其使用场景。

软引用

弱引用的使用比较简单,如Guava中的LocalCache中就是用了SoftReference来作缓存。

弱引用

弱引用是使用的比较多的,从上文的描述可知:对于一个「目标对象A」,若是还有强引用指向它,那么从一个弱引用就能够访问到A,一旦没有强引用指向它,那么就能够认为,从这个弱引用就访问不到A了(实际状况可能会有误差)。

根据这个特色,JDK中注释说到,弱引用一般用来作映射表( canonicalizing mapping),总结下来映射表有这样2个特色:

  1. 若是表中的Key(或者Value)还存在强引用,则能够经过Key访问到Value,反之则访问不到
    换句话说,只要有原始的Key,就能访问到Value。

  2. 映射表自己不会影响其中Key或者Value的GC

在JDK中有不少个地方使用了它的这个特色,下面是2个具备表明性的实例。

1. ThreadLocal

ThreadLocal的原理比较简单,线程中保持了一个以ThreadLocal为Key的ThreadLocal.ThreadLocalMap对象threadLocals,其中的Entry如代码1中所示:

//代码1
static class Entry extends WeakReference
  
  
  

  
 
  > { /** The value associated with this ThreadLocal. */ Object value; //其保持了对做为Key的ThreadLocal对象的弱引用 Entry(ThreadLocal 
 
   k, Object v) { super(k); value = v; } } 

 
  
  
  

 复制代码

其引用关系以下图所示:

ThreadLocal中的引用关系
ThreadLocal中的引用关系

从上图能够看出,当引用2被清除以后(ThreadLocal对象再也不使用),若是引用4为强引用,则不论引用1是否还存在,只要Thread对象还没死,则对象1和对象2永远不会被释放。

2. 动态代理

动态代理是Java世界一个十分重要的特性,对于须要作AOP的业务逻辑十分重要。JDK自己提供了基于反射的动态代理机制,其原理大体是要经过预先定义的接口(interface)来动态的生成代理类,并将之代理到InvocationHandler的实例上去。JDK的动态代理使用起来很简单,以下代码2中所示:

//代码2
package me.lk;

import java.lang.reflect.*;

public class TestProxy {
    /**
     * 两个预约义的须要被代理的接口
     */
    public static interface ProxiedInterface {

        void proxiedMethod();
    }
    public static interface ProxiedInterface2 {

        void proxiedMethod2();
    }

    /**
     * 真正的处理逻辑
     */
    public static class InvoHandler implements InvocationHandler {

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("in proxy:" + method.getName());
            //其余逻辑
            System.out.println("in proxy end");
            return null;
        }

    }
    public static void main(String[] args) {
        InvoHandler ih = new InvoHandler();
        ProxiedInterface proxy = (ProxiedInterface) Proxy.newProxyInstance(TestProxy.class.getClassLoader(), new Class[]{ProxiedInterface.class, ProxiedInterface2.class}, ih);
        proxy.proxiedMethod();
        ProxiedInterface2 p = (ProxiedInterface2) proxy;
        p.proxiedMethod2();
    }
}复制代码
动态代理的实现原理

其实现原理其实也很简单,就是在方法Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)中动态生成一个「实现了interfaces中全部接口」并「继承于Proxy」的代理类,并生成相应的对象。

//代码3
public static Object newProxyInstance(ClassLoader loader,
                                          Class
  
  
  

 [] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);

        final Class
  
  
  

 [] intfs = interfaces.clone();
        //验证真实调用者的权限
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        //查询或生成代理类
        Class
  
  
  

  cl = getProxyClass0(loader, intfs);

        //验证调用者对代理类的权限,并生成对象
        。。。省略代码
    }

    private static Class
  
  
  

  getProxyClass0(ClassLoader loader,
                                       Class
  
  
  

 ... interfaces) {
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }

        // 经过缓存获取代理类
        return proxyClassCache.get(loader, interfaces);
    }复制代码

生成动态类的逻辑在方法java.lang.reflect.Proxy.ProxyClassFactory.apply(ClassLoader, Class<?>[]),代码以下:

//代码4
@Override
public Class
  
  
  

  apply(ClassLoader loader, Class
  
  
  

 [] interfaces) {

    Map
  
  
  

  
 
  , Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length); //验证接口,验证接口是否重复,验证loader对接口的可见性 //生成包名和修饰符 //生成类 byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags); try { return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); } catch (ClassFormatError e) { /* * 生成失败 */ throw new IllegalArgumentException(e.toString()); } } 

 
  
  
  

 复制代码
动态代理中的缓存策略

为了更高效的使用动态代理,Proxy类中采用了缓存策略(代码3中的proxyClassCache )来缓存动态生成的代理类,因为这个缓存对象是静态的,也就是说一旦Proxy类被加载,proxyClassCache 极可能永远不会被GC回收,然而它必需要保持对其中的ClassLoader和Class的引用,若是这里使用强引用,则它们也随着proxyClassCache 永远不会被GC回收。

再也不使用的类和类加载器若是没法被GC,其内存泄漏的风险很大。因此WeakCache中设计为,「传入的类加载器」和「生成的代理类」为弱引用。

类和类加载器是相互引用的,而类加载器的内存泄漏可能会带来很严重的问题,有兴趣能够去看这篇文章:Reloading Java Classes 201: How do ClassLoader leaks happen?

//代码5
/**
 * a cache of proxy classes
 */
//ClassLoader    用来加载预约义接口(interface)和生成代理类的类加载器
//Class
  
  
  

 []     预约义接口(interface)
//Class
  
  
  

        生成的代理类
private static final WeakCache
  
  
  

 
  
  [], Class 
 
  > proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory()); /** * CacheKey containing a weakly referenced {@code key}. It registers * itself with the {@code refQueue} so that it can be used to expunge * the entry when the {@link WeakReference} is cleared. */ private static final class CacheKey 
 
  
    extends WeakReference 
   
     /** * A {@link Value} that weakly references the referent. */ private static final class CacheValue 
    
      extends WeakReference 
     
       implements Value 
       
      
     
    
   

 复制代码

从代码5中能够看出,WeakCache对象中保持了对ClassLoader(包装为CacheKey)和代理类(包装为CacheValue)的弱引用,因此当此类加载器和代理类再也不被强引用时,它们就会被回收。

存在的问题

然而,WeakCache的实现是有问题的,在java.lang.reflect.WeakCache.reverseMapjava.lang.reflect.WeakCache.valueFactory中的状态在极限状况下可能会出现不一样步,致使一个代理类被调用java.lang.reflect.Proxy.isProxyClass(Class<?>)的返回值不正确。具体能够参考Race Condition in java.lang.reflect.WeakCache

不过这个问题在JDK9中已经不存在了。

关于虚引用的GC行为

在上一节,并无列出虚引用的使用场景,由于它的使用场景十分单一。PhantomReference设计的目的就是能够在对象被回收以前收到通知(经过注册的队列),因此它没有不含注册队列的构造器(只有public PhantomReference(T referent, ReferenceQueue<? super T> q),但你仍能够传null进去),但这种场景在JDK里并无出现,也不多有开发者使用它。

从PhantomReference类的源代码可知,你永远没法经过它获取到它引用的那个对象(其get()方法永远返回null),可是它又能够阻止其引用的目标对象被GC回收。从上文可知,一般一个不可达(强不可达、软不可达、弱不可达)的对象会被finalize,而后被回收。但若是它在被回收前,GC发现它仍然是虚可达,那么它就不会回收这块内存,而这块内存又不能被访问到,那么这块内存就泄漏了。

想要虚引用的「目标对象」被回收,必须让「引用对象」自己不可达,或者显式地清除虚引用。因此若是使用不当,极可能会形成内存泄漏,这也是它使用范围不广的缘由之一。

代码6演示了这3种引用分别的GC行为:

//代码6
private static List
  
  
  

  
 
  > phantomRefs = new ArrayList<>(); private static List 
    
    > weaks = new ArrayList<>(); private static List 
      
      > softs = new ArrayList<>(); public static void testPhantomRefLeakOOM() { while(true) { //生成一个占用10M的内存的对象 Byte[] bytes = new Byte[1024 * 1024 * 10]; //使用软引用存储 // softs.add(new SoftReference(bytes)); //使用虚引用存储 PhantomReference pf = new PhantomReference(bytes, null); //使用弱引用存储 // weaks.add((new WeakReference(bytes))); phantomRefs.add(pf); //显式清除引用 // pf.clear(); //建议GC System.gc(); } }复制代码

以上代码展现了4种影响GC的行为,分别是:

1. 使用软引用的GC行为

GC日志以下,能够看到,当系统内存不够的时候(OOM以前),软引用会被清除,引起GC,释放内存。

2017-07-03T12:36:22.995+0800: [Full GC (System.gc()) [PSYoungGen: 40971K->40960K(76288K)] [ParOldGen: 492061K->492061K(506880K)] 533033K->533022K(583168K), [Metaspace: 2727K->2727K(1056768K)], 0.0610620 secs] [Times: user=0.23 sys=0.00, real=0.06 secs] 

2017-07-03T12:36:24.391+0800: [Full GC (System.gc()) [PSYoungGen: 40960K->40960K(76288K)] [ParOldGen: 1065502K->1065502K(1087488K)] 1106462K->1106462K(1163776K), [Metaspace: 

2017-07-03T12:36:32.291+0800: [Full GC (System.gc()) [PSYoungGen: 40962K->40962K(76288K)] [ParOldGen: 2581022K->2581022K(2621952K)] 2621985K->2621985K(2698240K), [Metaspace: 2727K->2727K(1056768K)], 0.3106258 secs] [Times: user=2.31 sys=0.00, real=0.31 secs] 
2017-07-03T12:36:32.610+0800: [GC (System.gc()) [PSYoungGen: 40962K->128K(76288K)] 2662945K->2663070K(2739712K), 0.6298054 secs] [Times: user=4.63 sys=0.00, real=0.63 secs] 
2017-07-03T12:36:33.240+0800: [Full GC (System.gc()) [PSYoungGen: 128K->0K(76288K)] [ParOldGen: 2662942K->2662945K(2663424K)] 2663070K->2662945K(2739712K), [Metaspace: 2727K->2727K(1056768K)], 0.2898513 secs] [Times: user=2.25 sys=0.00, real=0.29 secs] 

2017-07-03T12:36:34.096+0800: [Full GC (System.gc()) [PSYoungGen: 40960K->40960K(76288K)] [ParOldGen: 2744865K->2744865K(2746368K)] 2785825K->2785825K(2822656K), [Metaspace: 2727K->2727K(1056768K)], 0.3282086 secs] [Times: user=2.47 sys=0.00, real=0.33 secs] 
2017-07-03T12:36:34.425+0800: [Full GC (Ergonomics) [PSYoungGen: 40960K->40960K(76288K)] [ParOldGen: 2744865K->2744865K(2777088K)] 2785825K->2785825K(2853376K), [Metaspace: 2727K->2727K(1056768K)], 0.3061587 secs] [Times: user=2.32 sys=0.00, real=0.31 secs] 


2017-07-03T12:36:34.731+0800: [Full GC (Allocation Failure) [PSYoungGen: 40960K->0K(76288K)] [ParOldGen: 2744865K->531K(225280K)] 2785825K->531K(301568K), [Metaspace: 2727K->2727K(1056768K)], 0.1559132 secs] [Times: user=0.02 sys=0.14, real=0.16 secs] 
2017-07-03T12:36:34.890+0800: [GC (System.gc()) [PSYoungGen: 40960K->32K(76288K)] 41491K->82483K(301568K), 0.0304114 secs] [Times: user=0.14 sys=0.00, real=0.03 secs] 
2017-07-03T12:36:34.920+0800: [Full GC (System.gc()) [PSYoungGen: 32K->0K(76288K)] [ParOldGen: 82451K->41491K(225280K)] 82483K->41491K(301568K), [Metaspace: 2727K->2727K(1056768K)], 0.0179676 secs] [Times: user=0.05 sys=0.00, real=0.02 secs] 
2017-07-03T12:36:34.941+0800: [GC (System.gc()) [PSYoungGen: 41649K->32K(76288K)] 83140K->123443K(301568K), 0.0323917 secs] [Times: user=0.11 sys=0.00, real=0.03 secs] 
2017-07-03T12:36:34.973+0800: [Full GC (System.gc()) [PSYoungGen: 32K->0K(76288K)] [ParOldGen: 123411K->82451K(225280K)] 123443K->82451K(301568K), [Metaspace: 2727K->2727K(1056768K)], 0.0424672 secs] [Times: user=0.20 sys=0.00, real=0.04 secs] 
2017-07-03T12:36:35.414+0800: [Full GC (System.gc()) [PSYoungGen: 41011K->40960K(76288K)] [ParOldGen: 287252K->287252K(308224K)] 328264K->328212K(384512K), [Metaspace: 2727K->2727K(1056768K)], 0.0520262 secs] [Times: user=0.33 sys=0.00, real=0.05 secs] 

2017-07-03T12:36:48.569+0800: [Full GC (Ergonomics) [PSYoungGen: 40960K->40960K(76288K)] [ParOldGen: 2744854K->2744854K(2777088K)] 2785815K->2785815K(2853376K), [Metaspace: 2727K->2727K(1056768K)], 0.3476025 secs] [Times: user=2.45 sys=0.02, real=0.35 secs] 
2017-07-03T12:36:48.916+0800: [Full GC (Allocation Failure) [PSYoungGen: 40960K->0K(76288K)] [ParOldGen: 2744854K->534K(444928K)] 2785815K->534K(521216K), [Metaspace: 2727K->2727K(1056768K)], 0.1644360 secs] [Times: user=0.02 sys=0.16, real=0.17 secs] 
2017-07-03T12:36:49.084+0800: [GC (System.gc()) [PSYoungGen: 40960K->32K(76288K)] 41494K->82486K(521216K), 0.0444057 secs] [Times: user=0.22 sys=0.00, real=0.04 secs] 
2017-07-03T12:36:49.128+0800: [Full GC (System.gc()) [PSYoungGen: 32K->0K(76288K)] [ParOldGen: 82454K->41494K(444928K)] 82486K->41494K(521216K), [Metaspace: 2727K->2727K(1056768K)], 0.0288512 secs] [Times: user=0.11 sys=0.00, real=0.03 secs] 复制代码

2. 使用弱引用

GC日志以下,从中能够看到,弱引用所引用的目标对象,时时刻刻都在被GC。

2017-07-03T12:32:55.214+0800: [GC (System.gc()) [PSYoungGen: 43581K->728K(76288K)] 43581K->41696K(251392K), 0.0354037 secs] [Times: user=0.20 sys=0.00, real=0.04 secs] 
2017-07-03T12:32:55.252+0800: [Full GC (System.gc()) [PSYoungGen: 728K->0K(76288K)] [ParOldGen: 40968K->41502K(175104K)] 41696K->41502K(251392K), [Metaspace: 2726K->2726K(1056768K)], 0.0258447 secs] [Times: user=0.08 sys=0.00, real=0.03 secs] 

2017-07-03T12:32:55.533+0800: [Full GC (System.gc()) [PSYoungGen: 41309K->40960K(76288K)] [ParOldGen: 164381K->164381K(175104K)] 205690K->205341K(251392K), [Metaspace: 2726K->2726K(1056768K)], 0.0389489 secs] [Times: user=0.25 sys=0.00, real=0.04 secs] 

2017-07-03T12:32:57.413+0800: [Full GC (System.gc()) [PSYoungGen: 40960K->40960K(76288K)] [ParOldGen: 1024541K->1024541K(1046016K)] 1065502K->1065502K(1122304K), [Metaspace: 2726K->2726K(1056768K)], 0.1263574 secs] [Times: user=0.94 sys=0.00, real=0.13 secs] 

2017-07-03T12:33:05.364+0800: [Full GC (System.gc()) [PSYoungGen: 40962K->40962K(76288K)] [ParOldGen: 2581022K->2581022K(2621952K)] 2621984K->2621984K(2698240K), [Metaspace: 2726K->2726K(1056768K)], 0.2474419 secs] [Times: user=1.69 sys=0.00, real=0.25 secs] 

2017-07-03T12:33:07.447+0800: [Full GC (Ergonomics) [PSYoungGen: 40960K->40960K(76288K)] [ParOldGen: 2744864K->2744864K(2777088K)] 2785824K->2785824K(2853376K), [Metaspace: 2726K->2726K(1056768K)], 0.2825105 secs] [Times: user=1.79 sys=0.00, real=0.28 secs] 
2017-07-03T12:33:07.729+0800: [Full GC (Allocation Failure) [PSYoungGen: 40960K->40960K(76288K)] [ParOldGen: 2744864K->2744851K(2777088K)] 2785824K->2785812K(2853376K), [Metaspace: 2726K->2726K(1056768K)], 0.8902204 secs]Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at me.lk.TestReference.testPhantomRefLeakOOM(TestReference.java:109)
    at me.lk.TestReference.main(TestReference.java:50)
 [Times: user=3.79 sys=0.00, real=0.89 secs] 
Heap
 PSYoungGen      total 76288K, used 43025K [0x000000076b400000, 0x0000000770900000, 0x00000007c0000000)
  eden space 65536K, 65% used [0x000000076b400000,0x000000076de04408,0x000000076f400000)
  from space 10752K, 0% used [0x000000076f400000,0x000000076f400000,0x000000076fe80000)
  to   space 10752K, 0% used [0x000000076fe80000,0x000000076fe80000,0x0000000770900000)
 ParOldGen       total 2777088K, used 2744851K [0x00000006c1c00000, 0x000000076b400000, 0x000000076b400000)
  object space 2777088K, 98% used [0x00000006c1c00000,0x0000000769484fb8,0x000000076b400000)
 Metaspace       used 2757K, capacity 4490K, committed 4864K, reserved 1056768K
  class space    used 310K, capacity 386K, committed 512K, reserved 1048576K复制代码

3. 使用虚引用,不显式清除

GC日志以下,能够看到,不显式清除的虚引用会阻止GC回收内存,最终致使OOM。

2017-07-03T12:32:55.214+0800: [GC (System.gc()) [PSYoungGen: 43581K->728K(76288K)] 43581K->41696K(251392K), 0.0354037 secs] [Times: user=0.20 sys=0.00, real=0.04 secs] 
2017-07-03T12:32:55.252+0800: [Full GC (System.gc()) [PSYoungGen: 728K->0K(76288K)] [ParOldGen: 40968K->41502K(175104K)] 41696K->41502K(251392K), [Metaspace: 2726K->2726K(1056768K)], 0.0258447 secs] [Times: user=0.08 sys=0.00, real=0.03 secs] 

2017-07-03T12:32:55.533+0800: [Full GC (System.gc()) [PSYoungGen: 41309K->40960K(76288K)] [ParOldGen: 164381K->164381K(175104K)] 205690K->205341K(251392K), [Metaspace: 2726K->2726K(1056768K)], 0.0389489 secs] [Times: user=0.25 sys=0.00, real=0.04 secs] 

2017-07-03T12:32:57.413+0800: [Full GC (System.gc()) [PSYoungGen: 40960K->40960K(76288K)] [ParOldGen: 1024541K->1024541K(1046016K)] 1065502K->1065502K(1122304K), [Metaspace: 2726K->2726K(1056768K)], 0.1263574 secs] [Times: user=0.94 sys=0.00, real=0.13 secs] 

2017-07-03T12:33:05.364+0800: [Full GC (System.gc()) [PSYoungGen: 40962K->40962K(76288K)] [ParOldGen: 2581022K->2581022K(2621952K)] 2621984K->2621984K(2698240K), [Metaspace: 2726K->2726K(1056768K)], 0.2474419 secs] [Times: user=1.69 sys=0.00, real=0.25 secs] 

2017-07-03T12:33:07.447+0800: [Full GC (Ergonomics) [PSYoungGen: 40960K->40960K(76288K)] [ParOldGen: 2744864K->2744864K(2777088K)] 2785824K->2785824K(2853376K), [Metaspace: 2726K->2726K(1056768K)], 0.2825105 secs] [Times: user=1.79 sys=0.00, real=0.28 secs] 
2017-07-03T12:33:07.729+0800: [Full GC (Allocation Failure) [PSYoungGen: 40960K->40960K(76288K)] [ParOldGen: 2744864K->2744851K(2777088K)] 2785824K->2785812K(2853376K), [Metaspace: 2726K->2726K(1056768K)], 0.8902204 secs]Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at me.lk.TestReference.testPhantomRefLeakOOM(TestReference.java:109)
    at me.lk.TestReference.main(TestReference.java:50)
 [Times: user=3.79 sys=0.00, real=0.89 secs] 
Heap
 PSYoungGen      total 76288K, used 43025K [0x000000076b400000, 0x0000000770900000, 0x00000007c0000000)
  eden space 65536K, 65% used [0x000000076b400000,0x000000076de04408,0x000000076f400000)
  from space 10752K, 0% used [0x000000076f400000,0x000000076f400000,0x000000076fe80000)
  to   space 10752K, 0% used [0x000000076fe80000,0x000000076fe80000,0x0000000770900000)
 ParOldGen       total 2777088K, used 2744851K [0x00000006c1c00000, 0x000000076b400000, 0x000000076b400000)
  object space 2777088K, 98% used [0x00000006c1c00000,0x0000000769484fb8,0x000000076b400000)
 Metaspace       used 2757K, capacity 4490K, committed 4864K, reserved 1056768K
  class space    used 310K, capacity 386K, committed 512K, reserved 1048576K复制代码

4. 使用虚引用,显式清除

显式清除的虚引用,不会影响GC,其GC行为和弱引用十分类似。

2017-07-03T12:45:14.774+0800: [GC (System.gc()) [PSYoungGen: 43581K->696K(76288K)] 43581K->41664K(251392K), 0.0458469 secs] [Times: user=0.17 sys=0.00, real=0.05 secs] 
2017-07-03T12:45:14.820+0800: [Full GC (System.gc()) [PSYoungGen: 696K->0K(76288K)] [ParOldGen: 40968K->41502K(175104K)] 41664K->41502K(251392K), [Metaspace: 2726K->2726K(1056768K)], 0.0198788 secs] [Times: user=0.08 sys=0.00, real=0.02 secs] 
2017-07-03T12:45:14.842+0800: [GC (System.gc()) [PSYoungGen: 42231K->32K(76288K)] 83734K->82495K(251392K), 0.0367363 secs] [Times: user=0.22 sys=0.00, real=0.04 secs] 
2017-07-03T12:45:14.879+0800: [Full GC (System.gc()) [PSYoungGen: 32K->0K(76288K)] [ParOldGen: 82463K->41501K(175104K)] 82495K->41501K(251392K), [Metaspace: 2727K->2727K(1056768K)], 0.0198085 secs] [Times: user=0.08 sys=0.00, real=0.02 secs] 
2017-07-03T12:45:14.901+0800: [GC (System.gc()) [PSYoungGen: 41786K->32K(76288K)] 83287K->82493K(251392K), 0.0327529 secs] [Times: user=0.19 sys=0.00, real=0.03 secs] 
2017-07-03T12:45:14.934+0800: [Full GC (System.gc()) [PSYoungGen: 32K->0K(76288K)] [ParOldGen: 82461K->41501K(175104K)] 82493K->41501K(251392K), [Metaspace: 2727K->2727K(1056768K)], 0.0283782 secs] [Times: user=0.17 sys=0.00, real=0.03 secs] 
2017-07-03T12:45:14.964+0800: [GC (System.gc()) [PSYoungGen: 41497K->32K(76288K)] 82998K->82493K(251392K), 0.0336216 secs] [Times: user=0.20 sys=0.00, real=0.03 secs] 
2017-07-03T12:45:14.998+0800: [Full GC (System.gc()) [PSYoungGen: 32K->0K(76288K)] [ParOldGen: 82461K->41501K(175104K)] 82493K->41501K(251392K), [Metaspace: 2727K->2727K(1056768K)], 0.0211702 secs] [Times: user=0.13 sys=0.00, real=0.02 secs] 
2017-07-03T12:45:15.021+0800: [GC (System.gc()) [PSYoungGen: 41309K->32K(76288K)] 82810K->82493K(251392K), 0.0445368 secs] [Times: user=0.30 sys=0.00, real=0.05 secs] 
2017-07-03T12:45:15.066+0800: [Full GC (System.gc()) [PSYoungGen: 32K->0K(76288K)] [ParOldGen: 82461K->41501K(175104K)] 82493K->41501K(251392K), [Metaspace: 2727K->2727K(1056768K)], 0.0219968 secs] [Times: user=0.11 sys=0.00, real=0.02 secs] 
2017-07-03T12:45:15.090+0800: [GC (System.gc()) [PSYoungGen: 41186K->32K(76288K)] 82688K->82493K(251392K), 0.0436528 secs] [Times: user=0.36 sys=0.00, real=0.04 secs] 
2017-07-03T12:45:15.133+0800: [Full GC (System.gc()) [PSYoungGen: 32K->0K(76288K)] [ParOldGen: 82461K->41501K(175104K)] 82493K->41501K(251392K), [Metaspace: 2727K->2727K(1056768K)], 0.0219814 secs] [Times: user=0.11 sys=0.00, real=0.02 secs]复制代码
关注下面的标签,发现更多类似文章
评论

2017-07-03T12:36:22.995+0800: [Full GC (System.gc()) [PSYoungGen: 40971K->40960K(76288K)] [ParOldGen: 492061K->492061K(506880K)] 533033K->533022K(583168K), [Metaspace: 2727K->2727K(1056768K)], 0.0610620 secs] [Times: user=0.23 sys=0.00, real=0.06 secs] 2017-07-03T12:36:24.391+0800: [Full GC (System.gc()) [PSYoungGen: 40960K->40960K(76288K)] [ParOldGen: 1065502K->1065502K(1087488K)] 1106462K->1106462K(1163776K), [Metaspace: 2017-07-03T12:36:32.291+0800: [Full GC (System.gc()) [PSYoungGen: 40962K->40962K(76288K)] [ParOldGen: 2581022K->2581022K(2621952K)] 2621985K->2621985K(2698240K), [Metaspace: 2727K->2727K(1056768K)], 0.3106258 secs] [Times: user=2.31 sys=0.00, real=0.31 secs] 2017-07-03T12:36:32.610+0800: [GC (System.gc()) [PSYoungGen: 40962K->128K(76288K)] 2662945K->2663070K(2739712K), 0.6298054 secs] [Times: user=4.63 sys=0.00, real=0.63 secs] 2017-07-03T12:36:33.240+0800: [Full GC (System.gc()) [PSYoungGen: 128K->0K(76288K)] [ParOldGen: 2662942K->2662945K(2663424K)] 2663070K->2662945K(2739712K), [Metaspace: 2727K->2727K(1056768K)], 0.2898513 secs] [Times: user=2.25 sys=0.00, real=0.29 secs] 2017-07-03T12:36:34.096+0800: [Full GC (System.gc()) [PSYoungGen: 40960K->40960K(76288K)] [ParOldGen: 2744865K->2744865K(2746368K)] 2785825K->2785825K(2822656K), [Metaspace: 2727K->2727K(1056768K)], 0.3282086 secs] [Times: user=2.47 sys=0.00, real=0.33 secs] 2017-07-03T12:36:34.425+0800: [Full GC (Ergonomics) [PSYoungGen: 40960K->40960K(76288K)] [ParOldGen: 2744865K->2744865K(2777088K)] 2785825K->2785825K(2853376K), [Metaspace: 2727K->2727K(1056768K)], 0.3061587 secs] [Times: user=2.32 sys=0.00, real=0.31 secs] 2017-07-03T12:36:34.731+0800: [Full GC (Allocation Failure) [PSYoungGen: 40960K->0K(76288K)] [ParOldGen: 2744865K->531K(225280K)] 2785825K->531K(301568K), [Metaspace: 2727K->2727K(1056768K)], 0.1559132 secs] [Times: user=0.02 sys=0.14, real=0.16 secs] 2017-07-03T12:36:34.890+0800: [GC (System.gc()) [PSYoungGen: 40960K->32K(76288K)] 41491K->82483K(301568K), 0.0304114 secs] [Times: user=0.14 sys=0.00, real=0.03 secs] 2017-07-03T12:36:34.920+0800: [Full GC (System.gc()) [PSYoungGen: 32K->0K(76288K)] [ParOldGen: 82451K->41491K(225280K)] 82483K->41491K(301568K), [Metaspace: 2727K->2727K(1056768K)], 0.0179676 secs] [Times: user=0.05 sys=0.00, real=0.02 secs] 2017-07-03T12:36:34.941+0800: [GC (System.gc()) [PSYoungGen: 41649K->32K(76288K)] 83140K->123443K(301568K), 0.0323917 secs] [Times: user=0.11 sys=0.00, real=0.03 secs] 2017-07-03T12:36:34.973+0800: [Full GC (System.gc()) [PSYoungGen: 32K->0K(76288K)] [ParOldGen: 123411K->82451K(225280K)] 123443K->82451K(301568K), [Metaspace: 2727K->2727K(1056768K)], 0.0424672 secs] [Times: user=0.20 sys=0.00, real=0.04 secs] 2017-07-03T12:36:35.414+0800: [Full GC (System.gc()) [PSYoungGen: 41011K->40960K(76288K)] [ParOldGen: 287252K->287252K(308224K)] 328264K->328212K(384512K), [Metaspace: 2727K->2727K(1056768K)], 0.0520262 secs] [Times: user=0.33 sys=0.00, real=0.05 secs] 2017-07-03T12:36:48.569+0800: [Full GC (Ergonomics) [PSYoungGen: 40960K->40960K(76288K)] [ParOldGen: 2744854K->2744854K(2777088K)] 2785815K->2785815K(2853376K), [Metaspace: 2727K->2727K(1056768K)], 0.3476025 secs] [Times: user=2.45 sys=0.02, real=0.35 secs] 2017-07-03T12:36:48.916+0800: [Full GC (Allocation Failure) [PSYoungGen: 40960K->0K(76288K)] [ParOldGen: 2744854K->534K(444928K)] 2785815K->534K(521216K), [Metaspace: 2727K->2727K(1056768K)], 0.1644360 secs] [Times: user=0.02 sys=0.16, real=0.17 secs] 2017-07-03T12:36:49.084+0800: [GC (System.gc()) [PSYoungGen: 40960K->32K(76288K)] 41494K->82486K(521216K), 0.0444057 secs] [Times: user=0.22 sys=0.00, real=0.04 secs] 2017-07-03T12:36:49.128+0800: [Full GC (System.gc()) [PSYoungGen: 32K->0K(76288K)] [ParOldGen: 82454K->41494K(444928K)] 82486K->41494K(521216K), [Metaspace: 2727K->2727K(1056768K)], 0.0288512 secs] [Times: user=0.11 sys=0.00, real=0.03 secs] 复制代码2017-07-03T12:32:55.214+0800: [GC (System.gc()) [PSYoungGen: 43581K->728K(76288K)] 43581K->41696K(251392K), 0.0354037 secs] [Times: user=0.20 sys=0.00, real=0.04 secs] 2017-07-03T12:32:55.252+0800: [Full GC (System.gc()) [PSYoungGen: 728K->0K(76288K)] [ParOldGen: 40968K->41502K(175104K)] 41696K->41502K(251392K), [Metaspace: 2726K->2726K(1056768K)], 0.0258447 secs] [Times: user=0.08 sys=0.00, real=0.03 secs] 2017-07-03T12:32:55.533+0800: [Full GC (System.gc()) [PSYoungGen: 41309K->40960K(76288K)] [ParOldGen: 164381K->164381K(175104K)] 205690K->205341K(251392K), [Metaspace: 2726K->2726K(1056768K)], 0.0389489 secs] [Times: user=0.25 sys=0.00, real=0.04 secs] 2017-07-03T12:32:57.413+0800: [Full GC (System.gc()) [PSYoungGen: 40960K->40960K(76288K)] [ParOldGen: 1024541K->1024541K(1046016K)] 1065502K->1065502K(1122304K), [Metaspace: 2726K->2726K(1056768K)], 0.1263574 secs] [Times: user=0.94 sys=0.00, real=0.13 secs] 2017-07-03T12:33:05.364+0800: [Full GC (System.gc()) [PSYoungGen: 40962K->40962K(76288K)] [ParOldGen: 2581022K->2581022K(2621952K)] 2621984K->2621984K(2698240K), [Metaspace: 2726K->2726K(1056768K)], 0.2474419 secs] [Times: user=1.69 sys=0.00, real=0.25 secs] 2017-07-03T12:33:07.447+0800: [Full GC (Ergonomics) [PSYoungGen: 40960K->40960K(76288K)] [ParOldGen: 2744864K->2744864K(2777088K)] 2785824K->2785824K(2853376K), [Metaspace: 2726K->2726K(1056768K)], 0.2825105 secs] [Times: user=1.79 sys=0.00, real=0.28 secs] 2017-07-03T12:33:07.729+0800: [Full GC (Allocation Failure) [PSYoungGen: 40960K->40960K(76288K)] [ParOldGen: 2744864K->2744851K(2777088K)] 2785824K->2785812K(2853376K), [Metaspace: 2726K->2726K(1056768K)], 0.8902204 secs]Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at me.lk.TestReference.testPhantomRefLeakOOM(TestReference.java:109) at me.lk.TestReference.main(TestReference.java:50) [Times: user=3.79 sys=0.00, real=0.89 secs] Heap PSYoungGen total 76288K, used 43025K [0x000000076b400000, 0x0000000770900000, 0x00000007c0000000) eden space 65536K, 65% used [0x000000076b400000,0x000000076de04408,0x000000076f400000) from space 10752K, 0% used [0x000000076f400000,0x000000076f400000,0x000000076fe80000) to space 10752K, 0% used [0x000000076fe80000,0x000000076fe80000,0x0000000770900000) ParOldGen total 2777088K, used 2744851K [0x00000006c1c00000, 0x000000076b400000, 0x000000076b400000) object space 2777088K, 98% used [0x00000006c1c00000,0x0000000769484fb8,0x000000076b400000) Metaspace used 2757K, capacity 4490K, committed 4864K, reserved 1056768K class space used 310K, capacity 386K, committed 512K, reserved 1048576K复制代码2017-07-03T12:32:55.214+0800: [GC (System.gc()) [PSYoungGen: 43581K->728K(76288K)] 43581K->41696K(251392K), 0.0354037 secs] [Times: user=0.20 sys=0.00, real=0.04 secs] 2017-07-03T12:32:55.252+0800: [Full GC (System.gc()) [PSYoungGen: 728K->0K(76288K)] [ParOldGen: 40968K->41502K(175104K)] 41696K->41502K(251392K), [Metaspace: 2726K->2726K(1056768K)], 0.0258447 secs] [Times: user=0.08 sys=0.00, real=0.03 secs] 2017-07-03T12:32:55.533+0800: [Full GC (System.gc()) [PSYoungGen: 41309K->40960K(76288K)] [ParOldGen: 164381K->164381K(175104K)] 205690K->205341K(251392K), [Metaspace: 2726K->2726K(1056768K)], 0.0389489 secs] [Times: user=0.25 sys=0.00, real=0.04 secs] 2017-07-03T12:32:57.413+0800: [Full GC (System.gc()) [PSYoungGen: 40960K->40960K(76288K)] [ParOldGen: 1024541K->1024541K(1046016K)] 1065502K->1065502K(1122304K), [Metaspace: 2726K->2726K(1056768K)], 0.1263574 secs] [Times: user=0.94 sys=0.00, real=0.13 secs] 2017-07-03T12:33:05.364+0800: [Full GC (System.gc()) [PSYoungGen: 40962K->40962K(76288K)] [ParOldGen: 2581022K->2581022K(2621952K)] 2621984K->2621984K(2698240K), [Metaspace: 2726K->2726K(1056768K)], 0.2474419 secs] [Times: user=1.69 sys=0.00, real=0.25 secs] 2017-07-03T12:33:07.447+0800: [Full GC (Ergonomics) [PSYoungGen: 40960K->40960K(76288K)] [ParOldGen: 2744864K->2744864K(2777088K)] 2785824K->2785824K(2853376K), [Metaspace: 2726K->2726K(1056768K)], 0.2825105 secs] [Times: user=1.79 sys=0.00, real=0.28 secs] 2017-07-03T12:33:07.729+0800: [Full GC (Allocation Failure) [PSYoungGen: 40960K->40960K(76288K)] [ParOldGen: 2744864K->2744851K(2777088K)] 2785824K->2785812K(2853376K), [Metaspace: 2726K->2726K(1056768K)], 0.8902204 secs]Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at me.lk.TestReference.testPhantomRefLeakOOM(TestReference.java:109) at me.lk.TestReference.main(TestReference.java:50) [Times: user=3.79 sys=0.00, real=0.89 secs] Heap PSYoungGen total 76288K, used 43025K [0x000000076b400000, 0x0000000770900000, 0x00000007c0000000) eden space 65536K, 65% used [0x000000076b400000,0x000000076de04408,0x000000076f400000) from space 10752K, 0% used [0x000000076f400000,0x000000076f400000,0x000000076fe80000) to space 10752K, 0% used [0x000000076fe80000,0x000000076fe80000,0x0000000770900000) ParOldGen total 2777088K, used 2744851K [0x00000006c1c00000, 0x000000076b400000, 0x000000076b400000) object space 2777088K, 98% used [0x00000006c1c00000,0x0000000769484fb8,0x000000076b400000) Metaspace used 2757K, capacity 4490K, committed 4864K, reserved 1056768K class space used 310K, capacity 386K, committed 512K, reserved 1048576K复制代码2017-07-03T12:45:14.774+0800: [GC (System.gc()) [PSYoungGen: 43581K->696K(76288K)] 43581K->41664K(251392K), 0.0458469 secs] [Times: user=0.17 sys=0.00, real=0.05 secs] 2017-07-03T12:45:14.820+0800: [Full GC (System.gc()) [PSYoungGen: 696K->0K(76288K)] [ParOldGen: 40968K->41502K(175104K)] 41664K->41502K(251392K), [Metaspace: 2726K->2726K(1056768K)], 0.0198788 secs] [Times: user=0.08 sys=0.00, real=0.02 secs] 2017-07-03T12:45:14.842+0800: [GC (System.gc()) [PSYoungGen: 42231K->32K(76288K)] 83734K->82495K(251392K), 0.0367363 secs] [Times: user=0.22 sys=0.00, real=0.04 secs] 2017-07-03T12:45:14.879+0800: [Full GC (System.gc()) [PSYoungGen: 32K->0K(76288K)] [ParOldGen: 82463K->41501K(175104K)] 82495K->41501K(251392K), [Metaspace: 2727K->2727K(1056768K)], 0.0198085 secs] [Times: user=0.08 sys=0.00, real=0.02 secs] 2017-07-03T12:45:14.901+0800: [GC (System.gc()) [PSYoungGen: 41786K->32K(76288K)] 83287K->82493K(251392K), 0.0327529 secs] [Times: user=0.19 sys=0.00, real=0.03 secs] 2017-07-03T12:45:14.934+0800: [Full GC (System.gc()) [PSYoungGen: 32K->0K(76288K)] [ParOldGen: 82461K->41501K(175104K)] 82493K->41501K(251392K), [Metaspace: 2727K->2727K(1056768K)], 0.0283782 secs] [Times: user=0.17 sys=0.00, real=0.03 secs] 2017-07-03T12:45:14.964+0800: [GC (System.gc()) [PSYoungGen: 41497K->32K(76288K)] 82998K->82493K(251392K), 0.0336216 secs] [Times: user=0.20 sys=0.00, real=0.03 secs] 2017-07-03T12:45:14.998+0800: [Full GC (System.gc()) [PSYoungGen: 32K->0K(76288K)] [ParOldGen: 82461K->41501K(175104K)] 82493K->41501K(251392K), [Metaspace: 2727K->2727K(1056768K)], 0.0211702 secs] [Times: user=0.13 sys=0.00, real=0.02 secs] 2017-07-03T12:45:15.021+0800: [GC (System.gc()) [PSYoungGen: 41309K->32K(76288K)] 82810K->82493K(251392K), 0.0445368 secs] [Times: user=0.30 sys=0.00, real=0.05 secs] 2017-07-03T12:45:15.066+0800: [Full GC (System.gc()) [PSYoungGen: 32K->0K(76288K)] [ParOldGen: 82461K->41501K(175104K)] 82493K->41501K(251392K), [Metaspace: 2727K->2727K(1056768K)], 0.0219968 secs] [Times: user=0.11 sys=0.00, real=0.02 secs] 2017-07-03T12:45:15.090+0800: [GC (System.gc()) [PSYoungGen: 41186K->32K(76288K)] 82688K->82493K(251392K), 0.0436528 secs] [Times: user=0.36 sys=0.00, real=0.04 secs] 2017-07-03T12:45:15.133+0800: [Full GC (System.gc()) [PSYoungGen: 32K->0K(76288K)] [ParOldGen: 82461K->41501K(175104K)] 82493K->41501K(251392K), [Metaspace: 2727K->2727K(1056768K)], 0.0219814 secs] [Times: user=0.11 sys=0.00, real=0.02 secs]复制代码
相关文章
相关标签/搜索