一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - Java教程 - Java中的引用和動(dòng)態(tài)代理的實(shí)現(xiàn)詳解

Java中的引用和動(dòng)態(tài)代理的實(shí)現(xiàn)詳解

2021-02-18 12:26TheAlchemist Java教程

這篇文章主要介紹了Java中的引用和動(dòng)態(tài)代理的實(shí)現(xiàn)詳解,涉及Java中的引用類型,JVMGC的可達(dá)性分析,代理模式等相關(guān)內(nèi)容,具有一定參考價(jià)值,需要的朋友可以了解下。

我們知道,動(dòng)態(tài)代理(這里指jdk的動(dòng)態(tài)代理)與靜態(tài)代理的區(qū)別在于,其真實(shí)的代理類是動(dòng)態(tài)生成的。但具體是怎么生成,生成的代理類包含了哪些內(nèi)容,以什么形式存在,它為什么一定要以接口為基礎(chǔ)?

如果去看動(dòng)態(tài)代理的源代碼(java.lang.reflect.proxy),會(huì)發(fā)現(xiàn)其原理很簡(jiǎn)單(真正二進(jìn)制類文件的生成是在本地方法中完成,源代碼中沒有),但其中用到了一個(gè)緩沖類java.lang.reflect.weakcache<classloader,class<?>[],class<?>>,這個(gè)類用到了弱引用來構(gòu)建。

在jdk的3個(gè)特殊引用中,弱引用是使用范圍最廣的,它的特性也最清晰,相對(duì)而言,其他兩種邏輯稍顯晦澀,源碼中的注釋也語焉不詳。本文將簡(jiǎn)單介紹幾種引用的行為特征,然后分析一下弱引用的一些實(shí)際應(yīng)用場(chǎng)景,其中包含了動(dòng)態(tài)代理中的實(shí)現(xiàn)。本文將包含以下內(nèi)容:

jdk中的引用類型

不同引用類型對(duì)gc行為的影響

引用類型的實(shí)現(xiàn)

threadlocal對(duì)弱引用的使用

動(dòng)態(tài)代理對(duì)弱引用的實(shí)現(xiàn)

虛引用如何導(dǎo)致內(nèi)存泄漏

jdk中「引用(reference)」的類型

java的所有運(yùn)行邏輯都是基于引用的,其形態(tài)類似于不可變的指針,所以在java中會(huì)有一些很繞的概念,比如說,java中函數(shù)的傳參是值傳遞,但這里所說的值,其實(shí)是引用的值,所以你可以通過一個(gè)函數(shù)的參數(shù)來修改其對(duì)象的值。另一方面,java中還存在一些基本數(shù)據(jù)類型,它們沒有引用,傳遞的是真實(shí)的值,所以不能在函數(shù)內(nèi)部修改參數(shù)的值。

關(guān)于引用,java中有這樣幾種:

1.強(qiáng)引用

所有對(duì)象的引用默認(rèn)為強(qiáng)引用,普通代碼中,賦值語句之間傳遞的都是強(qiáng)引用,如果一個(gè)對(duì)象可以被某個(gè)線程(活著的,下同)通過強(qiáng)引用訪問到,則稱之為強(qiáng)可達(dá)的(stronglyreachable)。

強(qiáng)可達(dá)的對(duì)象不會(huì)被gc回收。

2.軟引用(softreference<t>)

當(dāng)一個(gè)對(duì)象不是強(qiáng)可達(dá)的,但可以被某個(gè)線程通過軟引用訪問到,則稱之為軟可達(dá)的(softlyreachable)。

軟可達(dá)的對(duì)象的引用只有在內(nèi)存不足時(shí)會(huì)被清除,使之可以被gc回收。在這一點(diǎn)上,jvm是不保證具體什么時(shí)候清除軟引用,但可以保證在oom之前會(huì)清除軟可達(dá)的對(duì)象。同時(shí),jvm也不保證軟可達(dá)的對(duì)象的回收順序,但oraclejdk的文檔中提到,最近創(chuàng)建和最近使用的軟可達(dá)對(duì)象往往會(huì)最后被回收,與lru類似。

關(guān)于軟可達(dá)的對(duì)象何時(shí)被回收,可以參考o(jì)racle的文檔。

3.弱引用(weakreference<t>)

當(dāng)一個(gè)對(duì)象不是強(qiáng)可達(dá)的,也不是軟可達(dá)的,但可以被某個(gè)線程通過弱引用訪問到,則稱之為弱可達(dá)的(weaklyreachable)。

弱引用是除了強(qiáng)引用之外,使用最廣泛的引用類型,它的特性也更簡(jiǎn)單,當(dāng)一個(gè)對(duì)象是弱可達(dá)時(shí),jvm就會(huì)清除這個(gè)對(duì)象上的弱引用,隨后對(duì)這個(gè)對(duì)象進(jìn)行回收動(dòng)作。

4.虛引用(phantomreference<t>)

當(dāng)一個(gè)對(duì)象,通過以上幾種可達(dá)性分析都不可達(dá),且已經(jīng)finalized,但有虛引用指向它,則它是虛可達(dá)的(phantomreachable)。

虛引用是行為最詭異,使用方法最難的引用,后邊會(huì)講到。

虛引用不會(huì)影響gc,它的get()方法永遠(yuǎn)返回null,唯一的用處就是在gcfinalize一個(gè)對(duì)象之后,它會(huì)被放到指定的隊(duì)列中去。關(guān)于這個(gè)隊(duì)列會(huì)在下邊說明。

不同gc行為背后的原理

jvmgc的可達(dá)性分析

jvm的gc通過可達(dá)性分析來判斷一個(gè)對(duì)象是否可被回收,其基本思路就是以gcroots為起點(diǎn)遍歷鏈路上所有對(duì)象,當(dāng)一個(gè)對(duì)象和gcroots之間沒有任何的直接或間接引用相連時(shí),就稱之為不可達(dá)對(duì)象,則證明此對(duì)象是不可用的。

而進(jìn)一步,java中又定義了如上所述的4種不同的可達(dá)性,用來實(shí)現(xiàn)更精細(xì)的gc策略。

finalaze和referencequeue

對(duì)于普通的強(qiáng)引用對(duì)象,如果其變成不可達(dá)之后,通常gc會(huì)進(jìn)行finalize(finalize主要目的是讓用戶可以自定義釋放資源的過程,通常是釋放本地方法中使用的資源),然后將它的對(duì)象銷毀回收,但對(duì)于本文中討論的3種引用,還有可能在這個(gè)過程中做一些別的事情:

gc根據(jù)約定的規(guī)則來決定是否清除這些引用

這方面上一節(jié)已經(jīng)講過了,每個(gè)引用類型都有約定的處理規(guī)則。

如果它們注冊(cè)了引用隊(duì)列,在finalize對(duì)象后,將引用的對(duì)象放入隊(duì)列。

主要用來使開發(fā)者可以得到對(duì)象被銷毀的通知,當(dāng)然,如虛引用這樣的,其引用不會(huì)自動(dòng)被清除,所以它可以阻止其所引用的對(duì)象被回收。

引用(java.lang.ref.reference<t>)對(duì)象的狀態(tài)

這里所說的「引用對(duì)象」指的是由類java.lang.ref.reference<t>生產(chǎn)的對(duì)象,這個(gè)對(duì)象上保持了「需要特殊處理的」對(duì)「目標(biāo)對(duì)象」的引用。

引用對(duì)象有4種狀態(tài),根據(jù)它與其注冊(cè)的隊(duì)列的關(guān)系,分為以下4種:

active

引用對(duì)象的初始狀態(tài),表示gc要按照特殊的邏輯來處理這個(gè)對(duì)象,大致方法就是按照上一節(jié)提到的。

pending

如果一個(gè)引用對(duì)象,其注冊(cè)了隊(duì)列,在入隊(duì)之前,會(huì)進(jìn)入這個(gè)狀態(tài)。

enqueued

一個(gè)引用對(duì)象入隊(duì)后,進(jìn)入這個(gè)狀態(tài)。

inactive

一個(gè)引用對(duì)象出隊(duì)后,或者沒有注冊(cè)隊(duì)列,其隊(duì)列是一個(gè)特殊的對(duì)象java.lang.ref.referencequeue.null,表示這個(gè)對(duì)象已經(jīng)沒有用了。

幾種引用的實(shí)際應(yīng)用

日常開發(fā)工作中,用到除強(qiáng)引用之外的引用的可能性很小,只有在處理一些性能敏感的邏輯時(shí),才需要考慮使用這些特殊的引用,下面就舉幾個(gè)相關(guān)的實(shí)際例子,分析其使用場(chǎng)景。

軟引用

弱引用的使用比較簡(jiǎn)單,如guava中的localcache中就是用了softreference來做緩存。

弱引用

弱引用是使用的比較多的,從上文的描述可知:對(duì)于一個(gè)「目標(biāo)對(duì)象a」,如果還有強(qiáng)引用指向它,那么從一個(gè)弱引用就可以訪問到a,一旦沒有強(qiáng)引用指向它,那么就可以認(rèn)為,從這個(gè)弱引用就訪問不到a了(實(shí)際情況可能會(huì)有偏差)。

根據(jù)這個(gè)特點(diǎn),jdk中注釋說到,弱引用通常用來做映射表(canonicalizingmapping),總結(jié)下來映射表有這樣2個(gè)特點(diǎn):

如果表中的key(或者value)還存在強(qiáng)引用,則可以通過key訪問到value,反之則訪問不到

換句話說,只要有原始的key,就能訪問到value。

映射表本身不會(huì)影響其中key或者value的gc

在jdk中有很多個(gè)地方使用了它的這個(gè)特點(diǎn),下面是2個(gè)具有代表性的實(shí)例。

1.threadlocal

threadlocal的原理比較簡(jiǎn)單,線程中保持了一個(gè)以threadlocal為key的threadlocal.threadlocalmap對(duì)象threadlocals,其中的entry如代碼1中所示:

?
1
2
3
4
5
6
7
8
9
10
//代碼1
static class entry extends weakreference<threadlocal<?>> {
  /** the value associated with this threadlocal. */
  object value;
  //其保持了對(duì)作為key的threadlocal對(duì)象的弱引用
  entry(threadlocal<?> k, object v) {
    super(k);
    value = v;
  }
}

其引用關(guān)系如下圖所示:

Java中的引用和動(dòng)態(tài)代理的實(shí)現(xiàn)詳解

threadlocal中的引用關(guān)系

從上圖可以看出,當(dāng)引用2被清除之后(threadlocal對(duì)象不再使用),如果引用4為強(qiáng)引用,則不論引用1是否還存在,只要thread對(duì)象還沒死,則對(duì)象1和對(duì)象2永遠(yuǎn)不會(huì)被釋放。

2.動(dòng)態(tài)代理

動(dòng)態(tài)代理是java世界一個(gè)十分重要的特性,對(duì)于需要做aop的業(yè)務(wù)邏輯十分重要。jdk本身提供了基于反射的動(dòng)態(tài)代理機(jī)制,其原理大致是要通過預(yù)先定義的接口(interface)來動(dòng)態(tài)的生成代理類,并將之代理到invocationhandler的實(shí)例上去。jdk的動(dòng)態(tài)代理使用起來很簡(jiǎn)單,如下代碼2中所示:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
//代碼2
package me.lk;
 
import java.lang.reflect.*;
 
public class testproxy {
  /**
   * 兩個(gè)預(yù)定義的需要被代理的接口
   */
  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();
  }
 
}

動(dòng)態(tài)代理的實(shí)現(xiàn)原理

關(guān)于java中的動(dòng)態(tài)代理,我們首先需要了解的是一種常用的設(shè)計(jì)模式--代理模式,而對(duì)于代理,根據(jù)創(chuàng)建代理類的時(shí)間點(diǎn),又可以分為靜態(tài)代理和動(dòng)態(tài)代理。

代理模式是常用的java設(shè)計(jì)模式,他的特征是代理類與委托類有同樣的接口,代理類主要負(fù)責(zé)為委托類預(yù)處理消息、過濾消息、把消息轉(zhuǎn)發(fā)給委托類,以及事后處理消息等。代理類與委托類之間通常會(huì)存在關(guān)聯(lián)關(guān)系,一個(gè)代理類的對(duì)象與一個(gè)委托類的對(duì)象關(guān)聯(lián),代理類的對(duì)象本身并不真正實(shí)現(xiàn)服務(wù),而是通過調(diào)用委托類的對(duì)象的相關(guān)方法,來提供特定的服務(wù)。簡(jiǎn)單的說就是,我們?cè)谠L問實(shí)際對(duì)象時(shí),是通過代理對(duì)象來訪問的,代理模式就是在訪問實(shí)際對(duì)象時(shí)引入一定程度的間接性,因?yàn)檫@種間接性,可以附加多種用途。

參閱:java設(shè)計(jì)模式之代理模式原理及實(shí)現(xiàn)代碼分享

其實(shí)現(xiàn)原理其實(shí)也很簡(jiǎn)單,就是在方法proxy.newproxyinstance(classloader loader, class<?>[] interfaces, invocationhandler h)中動(dòng)態(tài)生成一個(gè)「實(shí)現(xiàn)了interfaces中所有接口」并「繼承于proxy」的代理類,并生成相應(yīng)的對(duì)象。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//代碼3
public static object newproxyinstance(classloader loader,
                     class<?>[] interfaces,
                     invocationhandler h)
    throws illegalargumentexception
  {
    objects.requirenonnull(h);
    final class<?>[] intfs = interfaces.clone();
    //驗(yàn)證真實(shí)調(diào)用者的權(quán)限
    final securitymanager sm = system.getsecuritymanager();
    if (sm != null) {
        checkproxyaccess(reflection.getcallerclass(), loader, intfs);
    }
    //查詢或生成代理類
    class<?> cl = getproxyclass0(loader, intfs);
    //驗(yàn)證調(diào)用者對(duì)代理類的權(quán)限,并生成對(duì)象
    。。。省略代碼
}
private static class<?> getproxyclass0(classloader loader,
                    class<?>... interfaces) {
    if (interfaces.length > 65535) {
        throw new illegalargumentexception("interface limit exceeded");
    }
    // 通過緩存獲取代理類
    return proxyclasscache.get(loader, interfaces);
}

生成動(dòng)態(tài)類的邏輯在方法java.lang.reflect.proxy.proxyclassfactory.apply(classloader, class<?>[]),代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//代碼4
@override
public class<?> apply(classloader loader, class<?>[] interfaces) {
 
  map<class<?>, boolean> interfaceset = new identityhashmap<>(interfaces.length);
  //驗(yàn)證接口,驗(yàn)證接口是否重復(fù),驗(yàn)證loader對(duì)接口的可見性
  
  //生成包名和修飾符
 
  //生成類
  byte[] proxyclassfile = proxygenerator.generateproxyclass(
    proxyname, interfaces, accessflags);
  try {
    return defineclass0(loader, proxyname,
              proxyclassfile, 0, proxyclassfile.length);
  } catch (classformaterror e) {
    /*
     * 生成失敗
     */
    throw new illegalargumentexception(e.tostring());
  }
}

動(dòng)態(tài)代理中的緩存策略

為了更高效的使用動(dòng)態(tài)代理,proxy類中采用了緩存策略(代碼3中的proxyclasscache )來緩存動(dòng)態(tài)生成的代理類,由于這個(gè)緩存對(duì)象是靜態(tài)的,也就是說一旦proxy類被加載,proxyclasscache 很可能永遠(yuǎn)不會(huì)被gc回收,然而它必須要保持對(duì)其中的classloader和class的引用,如果這里使用強(qiáng)引用,則它們也隨著proxyclasscache 永遠(yuǎn)不會(huì)被gc回收。

不再使用的類和類加載器如果無法被gc,其內(nèi)存泄漏的風(fēng)險(xiǎn)很大。所以weakcache中設(shè)計(jì)為,「?jìng)魅氲念惣虞d器」和「生成的代理類」為弱引用。

類和類加載器是相互引用的,而類加載器的內(nèi)存泄漏可能會(huì)帶來很嚴(yán)重的問題,有興趣可以去看這篇文章:reloading java classes 201: how do classloader leaks happen?

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//代碼5
/**
 * a cache of proxy classes
 */
//classloader  用來加載預(yù)定義接口(interface)和生成代理類的類加載器
//class<?>[]   預(yù)定義接口(interface)
//class<?>    生成的代理類
private static final weakcache<classloader, class<?>[], 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<k> extends weakreference<k>
 
/**
 * a {@link value} that weakly references the referent.
 */
private static final class cachevalue<v>
  extends weakreference<v> implements value<v>

從代碼5中可以看出,weakcache對(duì)象中保持了對(duì)classloader(包裝為cachekey)和代理類(包裝為cachevalue)的弱引用,所以當(dāng)此類加載器和代理類不再被強(qiáng)引用時(shí),它們就會(huì)被回收。

存在的問題

然而,weakcache的實(shí)現(xiàn)是有問題的,在java.lang.reflect.weakcache.reversemap和java.lang.reflect.weakcache.valuefactory中的狀態(tài)在極限情況下可能會(huì)出現(xiàn)不同步,導(dǎo)致一個(gè)代理類被調(diào)用java.lang.reflect.proxy.isproxyclass(class<?>)的返回值不正確。具體可以參考raceconditioninjava.lang.reflect.weakcache。

不過這個(gè)問題在jdk9中已經(jīng)不存在了。

關(guān)于虛引用的gc行為

在上一節(jié),并沒有列出虛引用的使用場(chǎng)景,因?yàn)樗氖褂脠?chǎng)景十分單一。phantomreference設(shè)計(jì)的目的就是可以在對(duì)象被回收之前收到通知(通過注冊(cè)的隊(duì)列),所以它沒有不含注冊(cè)隊(duì)列的構(gòu)造器(只有publicphantomreference(treferent,referencequeue<?supert>q),但你仍可以傳null進(jìn)去),但這種場(chǎng)景在jdk里并沒有出現(xiàn),也很少有開發(fā)者使用它。

從phantomreference類的源代碼可知,你永遠(yuǎn)無法通過它獲取到它引用的那個(gè)對(duì)象(其get()方法永遠(yuǎn)返回null),但是它又可以阻止其引用的目標(biāo)對(duì)象被gc回收。從上文可知,通常一個(gè)不可達(dá)(強(qiáng)不可達(dá)、軟不可達(dá)、弱不可達(dá))的對(duì)象會(huì)被finalize,然后被回收。但如果它在被回收前,gc發(fā)現(xiàn)它仍然是虛可達(dá),那么它就不會(huì)回收這塊內(nèi)存,而這塊內(nèi)存又不能被訪問到,那么這塊內(nèi)存就泄漏了。

想要虛引用的「目標(biāo)對(duì)象」被回收,必須讓「引用對(duì)象」本身不可達(dá),或者顯式地清除虛引用。所以如果使用不當(dāng),很可能會(huì)造成內(nèi)存泄漏,這也是它使用范圍不廣的原因之一。

代碼6演示了這3種引用分別的gc行為:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//代碼6
private static list<phantomreference<object>> phantomrefs = new arraylist<>();
private static list<weakreference<object>> weaks = new arraylist<>();
private static list<softreference<object>> softs = new arraylist<>();
 
public static void testphantomrefleakoom() {
  while(true) {
    //生成一個(gè)占用10m的內(nèi)存的對(duì)象
    byte[] bytes = new byte[1024 * 1024 * 10];
    //使用軟引用存儲(chǔ)
//  softs.add(new softreference<object>(bytes));
    //使用虛引用存儲(chǔ)
    phantomreference<object> pf = new phantomreference<object>(bytes, null);
    //使用弱引用存儲(chǔ)
//  weaks.add((new weakreference<object>(bytes)));
    phantomrefs.add(pf);
    //顯式清除引用
//  pf.clear();
    //建議gc
    system.gc();
  }
}

以上代碼展示了4種影響gc的行為,分別是:

1. 使用軟引用的gc行為

gc日志如下,可以看到,當(dāng)系統(tǒng)內(nèi)存不夠的時(shí)候(oom之前),軟引用會(huì)被清除,引發(fā)gc,釋放內(nèi)存。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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日志如下,從中可以看到,弱引用所引用的目標(biāo)對(duì)象,時(shí)時(shí)刻刻都在被gc。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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日志如下,可以看到,不顯式清除的虛引用會(huì)阻止gc回收內(nèi)存,最終導(dǎo)致oom。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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. 使用虛引用,顯式清除

顯式清除的虛引用,不會(huì)影響gc,其gc行為和弱引用十分相似。

?
1
2
3
4
5
6
7
8
9
10
11
12
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]

總結(jié)

以上就是本文關(guān)于java中的引用和動(dòng)態(tài)代理的實(shí)現(xiàn)詳解的全部?jī)?nèi)容,希望對(duì)大家有所幫助。如有不足之處,歡迎留言指出。感謝朋友們對(duì)本站的支持。

原文鏈接:http://www.jianshu.com/p/77dfeccac85d

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: a国产在线| 撕开老师的丝袜白丝扒开粉嫩的小 | sese在线| 韩国三级日本三级香港三级黄 | 欧美激情精品久久久久久不卡 | 脱了白丝校花的内裤猛烈进入 | 精品高潮呻吟99AV无码 | 91入口免费网站大全 | 99re精品在线 | 国产成人在线综合 | 国产福利视频一区二区微拍 | 四虎影视网站 | ova巨公主催眠1在线观看 | 91短视频在线播放 | 五月色天在线视频综合观看 | 国产成人在线免费观看 | 国产欧美视频高清va在线观看 | 青草视频免费 | h玉足嫩脚嗯啊白丝 | 国产精品成人 | 天天射寡妇射 | 王小军怎么了最新消息 | 午夜影院网页 | 亚洲国产精品久久网午夜 | 青青草原在线免费 | 四虎在线播放 | 糖心vlog麻豆精东影业传媒 | 国产成人在线视频播放 | 小伙无套内射老女人 | 国产高清好大好夹受不了了 | 52av我爱avhaose01 51香蕉视频 | 国产剧情麻豆刘玥视频 | 丰满岳乱妇在线观看视频国产 | 色老板最新网站视频地址 | 国产精品免费视频一区一 | 成人免费一区二区三区在线观看 | 国产一区日韩二区欧美三区 | 国色天香社区视频在线观看免费完整版 | 精品一区二区三区免费站 | chinese军人@gay | 日本花季传媒2020旧版安卓 |