2019年Java大廠面試題講解(周陽) 之 Java中的強(qiáng)引用/軟引用/弱引用/虛引用

      網(wǎng)友投稿 869 2022-05-29

      Java中的引用

      前言

      整體架構(gòu)

      強(qiáng)引用

      軟引用

      弱引用

      軟引用和弱引用的使用場(chǎng)景

      WeakHashMap是什么?

      虛引用

      概念

      場(chǎng)景

      引用隊(duì)列 ReferenceQueue

      GCRoots和四大引用小總結(jié)

      前言

      在原來的時(shí)候,我們談到一個(gè)類的實(shí)例化

      Person p = new Person()

      1

      在等號(hào)的左邊,就是一個(gè)對(duì)象的引用,存儲(chǔ)在棧中

      而等號(hào)右邊,就是實(shí)例化的對(duì)象,存儲(chǔ)在堆中

      其實(shí)這樣的一個(gè)引用關(guān)系,就被稱為強(qiáng)引用

      整體架構(gòu)

      強(qiáng)引用

      當(dāng)內(nèi)存不足的時(shí)候,JVM開始垃圾回收,對(duì)于強(qiáng)引用的對(duì)象,就算是出現(xiàn)了OOM也不會(huì)對(duì)該對(duì)象進(jìn)行回收,打死也不回收~!

      強(qiáng)引用是我們最常見的普通對(duì)象引用,只要還有一個(gè)強(qiáng)引用指向一個(gè)對(duì)象,就能表明對(duì)象還“活著”,垃圾收集器不會(huì)碰這種對(duì)象。在Java中最常見的就是強(qiáng)引用,把一個(gè)對(duì)象賦給一個(gè)引用變量,這個(gè)引用變量就是一個(gè)強(qiáng)引用。當(dāng)一個(gè)對(duì)象被強(qiáng)引用變量引用時(shí),它處于可達(dá)狀態(tài),它是不可能被垃圾回收機(jī)制回收的,即使該對(duì)象以后永遠(yuǎn)都不會(huì)被用到,JVM也不會(huì)回收,因此強(qiáng)引用是造成Java內(nèi)存泄漏的主要原因之一。

      對(duì)于一個(gè)普通的對(duì)象,如果沒有其它的引用關(guān)系,只要超過了引用的作用于或者顯示地將相應(yīng)(強(qiáng))引用賦值為null,一般可以認(rèn)為就是可以被垃圾收集的了(當(dāng)然具體回收時(shí)機(jī)還是要看垃圾回收策略)

      強(qiáng)引用小例子:

      /** * 強(qiáng)引用 * @author: 輕狂書生FS * @create: 2020-04-23-16:25 */ public class StrongReferenceDemo { public static void main(String[] args) { // 這樣定義的默認(rèn)就是強(qiáng)應(yīng)用 Object obj1 = new Object(); // 使用第二個(gè)引用,指向剛剛創(chuàng)建的Object對(duì)象 Object obj2 = obj1; // 置空 obj1 = null; // 垃圾回收 System.gc(); System.out.println(obj1); System.out.println(obj2); } }

      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

      輸出結(jié)果我們能夠發(fā)現(xiàn),即使 obj1 被設(shè)置成了null,然后調(diào)用gc進(jìn)行回收,但是也沒有回收實(shí)例出來的對(duì)象,obj2還是能夠指向該地址,也就是說垃圾回收器,并沒有將該對(duì)象進(jìn)行垃圾回收

      null java.lang.Object@14ae5a5

      1

      2

      軟引用

      軟引用是一種相對(duì)弱化了一些的引用,需要用Java.lang.ref.SoftReference類來實(shí)現(xiàn),可以讓對(duì)象豁免一些垃圾收集,對(duì)于只有軟引用的對(duì)象來講:

      當(dāng)系統(tǒng)內(nèi)存充足時(shí),它不會(huì)被回收

      當(dāng)系統(tǒng)內(nèi)存不足時(shí),它會(huì)被回收

      軟引用通常在對(duì)內(nèi)存敏感的程序中,比如高速緩存就用到了軟引用,內(nèi)存夠用 的時(shí)候就保留,不夠用就回收

      具體使用

      /** * 軟引用 * * @author: 輕狂書生FS * @create: 2020-04-23-16:39 */ public class SoftReferenceDemo { /** * 內(nèi)存夠用的時(shí)候 */ public static void softRefMemoryEnough() { // 創(chuàng)建一個(gè)強(qiáng)應(yīng)用 Object o1 = new Object(); // 創(chuàng)建一個(gè)軟引用 SoftReference softReference = new SoftReference<>(o1); System.out.println(o1); System.out.println(softReference.get()); o1 = null; // 手動(dòng)GC System.gc(); System.out.println(o1); System.out.println(softReference.get()); } /** * JVM配置,故意產(chǎn)生大對(duì)象并配置小的內(nèi)存,讓它的內(nèi)存不夠用了導(dǎo)致OOM,看軟引用的回收情況 * -Xms5m -Xmx5m -XX:+PrintGCDetails */ public static void softRefMemoryNoEnough() { System.out.println("========================"); // 創(chuàng)建一個(gè)強(qiáng)應(yīng)用 Object o1 = new Object(); // 創(chuàng)建一個(gè)軟引用 SoftReference softReference = new SoftReference<>(o1); System.out.println(o1); System.out.println(softReference.get()); o1 = null; // 模擬OOM自動(dòng)GC try { // 創(chuàng)建30M的大對(duì)象 byte[] bytes = new byte[30 * 1024 * 1024]; } catch (Exception e) { e.printStackTrace(); } finally { System.out.println(o1); System.out.println(softReference.get()); } } public static void main(String[] args) { softRefMemoryEnough(); softRefMemoryNoEnough(); } }

      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

      42

      43

      44

      45

      46

      47

      48

      49

      50

      51

      52

      53

      54

      55

      56

      57

      58

      59

      60

      61

      62

      63

      64

      我們寫了兩個(gè)方法,一個(gè)是內(nèi)存夠用的時(shí)候,一個(gè)是內(nèi)存不夠用的時(shí)候

      我們首先查看內(nèi)存夠用的時(shí)候,首先輸出的是 o1 和 軟引用的 softReference,我們都能夠看到值

      然后我們把o1設(shè)置為null,執(zhí)行手動(dòng)GC后,我們發(fā)現(xiàn)softReference的值還存在,說明內(nèi)存充足的時(shí)候,軟引用的對(duì)象不會(huì)被回收

      java.lang.Object@14ae5a5 java.lang.Object@14ae5a5 [GC (System.gc()) [PSYoungGen: 1396K->504K(1536K)] 1504K->732K(5632K), 0.0007842 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC (System.gc()) [PSYoungGen: 504K->0K(1536K)] [ParOldGen: 228K->651K(4096K)] 732K->651K(5632K), [Metaspace: 3480K->3480K(1056768K)], 0.0058450 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] null java.lang.Object@14ae5a5

      1

      2

      3

      4

      5

      6

      7

      8

      下面我們看當(dāng)內(nèi)存不夠的時(shí)候,我們使用了JVM啟動(dòng)參數(shù)配置,給初始化堆內(nèi)存為5M

      -Xms5m -Xmx5m -XX:+PrintGCDetails

      1

      但是在創(chuàng)建對(duì)象的時(shí)候,我們創(chuàng)建了一個(gè)30M的大對(duì)象

      // 創(chuàng)建30M的大對(duì)象 byte[] bytes = new byte[30 * 1024 * 1024];

      1

      2

      這就必然會(huì)觸發(fā)垃圾回收機(jī)制,這也是中間出現(xiàn)的垃圾回收過程,最后看結(jié)果我們發(fā)現(xiàn),o1 和 softReference都被回收了,因此說明,軟引用在內(nèi)存不足的時(shí)候,會(huì)自動(dòng)回收

      java.lang.Object@7f31245a java.lang.Object@7f31245a [GC (Allocation Failure) [PSYoungGen: 31K->160K(1536K)] 682K->811K(5632K), 0.0003603 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [GC (Allocation Failure) [PSYoungGen: 160K->96K(1536K)] 811K->747K(5632K), 0.0006385 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC (Allocation Failure) [PSYoungGen: 96K->0K(1536K)] [ParOldGen: 651K->646K(4096K)] 747K->646K(5632K), [Metaspace: 3488K->3488K(1056768K)], 0.0067976 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] [GC (Allocation Failure) [PSYoungGen: 0K->0K(1536K)] 646K->646K(5632K), 0.0004024 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC (Allocation Failure) [PSYoungGen: 0K->0K(1536K)] [ParOldGen: 646K->627K(4096K)] 646K->627K(5632K), [Metaspace: 3488K->3488K(1056768K)], 0.0065506 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] null null

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      弱引用

      不管內(nèi)存是否夠,只要有GC操作就會(huì)進(jìn)行回收

      弱引用需要用 java.lang.ref.WeakReference 類來實(shí)現(xiàn),它比軟引用生存期更短

      對(duì)于只有弱引用的對(duì)象來說,只要垃圾回收機(jī)制一運(yùn)行,不管JVM的內(nèi)存空間是否足夠,都會(huì)回收該對(duì)象占用的空間。

      /** * 弱引用 * * @author: 輕狂書生FS * @create: 2020-04-24-10:18 */ public class WeakReferenceDemo { public static void main(String[] args) { Object o1 = new Object(); WeakReference weakReference = new WeakReference<>(o1); System.out.println(o1); System.out.println(weakReference.get()); o1 = null; System.gc(); System.out.println(o1); System.out.println(weakReference.get()); } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      我們看結(jié)果,能夠發(fā)現(xiàn),我們并沒有制造出OOM內(nèi)存溢出,而只是調(diào)用了一下GC操作,垃圾回收就把它給收集了

      java.lang.Object@14ae5a5 java.lang.Object@14ae5a5 [GC (System.gc()) [PSYoungGen: 5246K->808K(76288K)] 5246K->816K(251392K), 0.0008236 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC (System.gc()) [PSYoungGen: 808K->0K(76288K)] [ParOldGen: 8K->675K(175104K)] 816K->675K(251392K), [Metaspace: 3494K->3494K(1056768K)], 0.0035953 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] null null

      1

      2

      3

      4

      5

      6

      7

      8

      軟引用和弱引用的使用場(chǎng)景

      場(chǎng)景:假如有一個(gè)應(yīng)用需要讀取大量的本地圖片

      如果每次讀取圖片都從硬盤讀取則會(huì)嚴(yán)重影響性能

      如果一次性全部加載到內(nèi)存中,又可能造成內(nèi)存溢出

      此時(shí)使用軟引用可以解決這個(gè)問題

      設(shè)計(jì)思路:使用HashMap來保存圖片的路徑和相應(yīng)圖片對(duì)象關(guān)聯(lián)的軟引用之間的映射關(guān)系,在內(nèi)存不足時(shí),JVM會(huì)自動(dòng)回收這些緩存圖片對(duì)象所占的空間,從而有效地避免了OOM的問題

      Map> imageCache = new HashMap>();

      1

      WeakHashMap是什么?

      比如一些常常和底層打交道的,mybatis等,底層都應(yīng)用到了WeakHashMap

      WeakHashMap和HashMap類似,只不過它的Key是使用了弱引用的,也就是說,當(dāng)執(zhí)行GC的時(shí)候,HashMap中的key會(huì)進(jìn)行回收,下面我們使用例子來測(cè)試一下

      我們使用了兩個(gè)方法,一個(gè)是普通的HashMap方法

      我們輸入一個(gè)Key-Value鍵值對(duì),然后讓它的key置空,然后在查看結(jié)果

      private static void myHashMap() { Map map = new HashMap<>(); Integer key = new Integer(1); String value = "HashMap"; map.put(key, value); System.out.println(map); key = null; System.gc(); System.out.println(map); }

      1

      2019年Java大廠面試題講解(周陽) 之 Java中的強(qiáng)引用/軟引用/弱引用/虛引用

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      第二個(gè)是使用了WeakHashMap,完整代碼如下

      /** * WeakHashMap * @author: 陌溪 * @create: 2020-03-24-11:33 */ public class WeakHashMapDemo { public static void main(String[] args) { myHashMap(); System.out.println("=========="); myWeakHashMap(); } private static void myHashMap() { Map map = new HashMap<>(); Integer key = new Integer(1); String value = "HashMap"; map.put(key, value); System.out.println(map); key = null; System.gc(); System.out.println(map); } private static void myWeakHashMap() { Map map = new WeakHashMap<>(); Integer key = new Integer(1); String value = "WeakHashMap"; map.put(key, value); System.out.println(map); key = null; System.gc(); System.out.println(map); } }

      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

      42

      最后輸出結(jié)果為:

      {1=HashMap} {1=HashMap} ========== {1=WeakHashMap} {}

      1

      2

      3

      4

      5

      從這里我們看到,對(duì)于普通的HashMap來說,key置空并不會(huì)影響,HashMap的鍵值對(duì),因?yàn)檫@個(gè)屬于強(qiáng)引用,不會(huì)被垃圾回收。

      但是WeakHashMap,在進(jìn)行GC操作后,弱引用的就會(huì)被回收

      虛引用

      概念

      虛引用又稱為幽靈引用,需要java.lang.ref.PhantomReference 類來實(shí)現(xiàn)

      顧名思義,就是形同虛設(shè),與其他幾種引用都不同,虛引用并不會(huì)決定對(duì)象的生命周期。

      如果一個(gè)對(duì)象持有虛引用,那么它就和沒有任何引用一樣,在任何時(shí)候都可能被垃圾回收器回收,它不能單獨(dú)使用也不能通過它訪問對(duì)象,虛引用必須和引用隊(duì)列ReferenceQueue聯(lián)合使用。

      虛引用的主要作用和跟蹤對(duì)象被垃圾回收的狀態(tài),僅僅是提供一種確保對(duì)象被finalize以后,做某些事情的機(jī)制。

      PhantomReference的get方法總是返回null,因此無法訪問對(duì)象的引用對(duì)象。其意義在于說明一個(gè)對(duì)象已經(jīng)進(jìn)入finalization階段,可以被gc回收,用來實(shí)現(xiàn)比finalization機(jī)制更靈活的回收操作

      換句話說,設(shè)置虛引用關(guān)聯(lián)的唯一目的,就是在這個(gè)對(duì)象被收集器回收的時(shí)候,收到一個(gè)系統(tǒng)通知或者后續(xù)添加進(jìn)一步的處理,Java技術(shù)允許使用finalize()方法在垃圾收集器將對(duì)象從內(nèi)存中清除出去之前,做必要的清理工作

      這個(gè)就相當(dāng)于Spring AOP里面的后置通知

      場(chǎng)景

      一般用于在回收時(shí)候做通知相關(guān)操作

      引用隊(duì)列 ReferenceQueue

      軟引用,弱引用,虛引用在回收之前,需要在引用隊(duì)列保存一下

      我們?cè)诔跏蓟娜跻没蛘咛撘玫臅r(shí)候,可以傳入一個(gè)引用隊(duì)列

      Object o1 = new Object(); // 創(chuàng)建引用隊(duì)列 ReferenceQueue referenceQueue = new ReferenceQueue<>(); // 創(chuàng)建一個(gè)弱引用 WeakReference weakReference = new WeakReference<>(o1, referenceQueue);

      1

      2

      3

      4

      5

      6

      7

      那么在進(jìn)行GC回收的時(shí)候,弱引用和虛引用的對(duì)象都會(huì)被回收,但是在回收之前,它會(huì)被送至引用隊(duì)列中

      完整代碼如下:

      /** * 虛引用 * * @author: 輕狂書生FS * @create: 2020-04-24-12:09 */ public class PhantomReferenceDemo { public static void main(String[] args) { Object o1 = new Object(); // 創(chuàng)建引用隊(duì)列 ReferenceQueue referenceQueue = new ReferenceQueue<>(); // 創(chuàng)建一個(gè)弱引用 WeakReference weakReference = new WeakReference<>(o1, referenceQueue); // 創(chuàng)建一個(gè)弱引用 // PhantomReference weakReference = new PhantomReference<>(o1, referenceQueue); System.out.println(o1); System.out.println(weakReference.get()); // 取隊(duì)列中的內(nèi)容 System.out.println(referenceQueue.poll()); o1 = null; System.gc(); System.out.println("執(zhí)行GC操作"); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(o1); System.out.println(weakReference.get()); // 取隊(duì)列中的內(nèi)容 System.out.println(referenceQueue.poll()); } }

      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

      42

      43

      運(yùn)行結(jié)果

      java.lang.Object@14ae5a5 java.lang.Object@14ae5a5 null 執(zhí)行GC操作 null null java.lang.ref.WeakReference@7f3124

      1

      2

      3

      4

      5

      6

      7

      從這里我們能看到,在進(jìn)行垃圾回收后,我們?nèi)跻脤?duì)象,也被設(shè)置成null,但是在隊(duì)列中還能夠?qū)С鲈撘玫膶?shí)例,這就說明在回收之前,該弱引用的實(shí)例被放置引用隊(duì)列中了,我們可以通過引用隊(duì)列進(jìn)行一些后置操作

      GCRoots和四大引用小總結(jié)

      紅色部分在垃圾回收之外,也就是強(qiáng)引用的

      藍(lán)色部分:屬于軟引用,在內(nèi)存不夠的時(shí)候,才回收

      虛引用和弱引用:每次垃圾回收的時(shí)候,都會(huì)被干掉,但是它在干掉之前還會(huì)存在引用隊(duì)列中,我們可以通過引用隊(duì)列進(jìn)行一些通知機(jī)制

      Java JVM

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:簡(jiǎn)單工廠、工廠方法和抽象工廠之間的區(qū)別
      下一篇:蟲子 指令 linux開發(fā)必備,007又怎樣,加快太空時(shí)代步伐
      相關(guān)文章
      亚洲成a人片7777| 亚洲视频免费一区| 亚洲午夜久久久精品电影院| 亚洲国产天堂在线观看| 最新国产AV无码专区亚洲| 亚洲欧洲精品成人久久曰影片| 亚洲成aⅴ人片久青草影院按摩| 亚洲午夜电影一区二区三区| 亚洲午夜精品一区二区公牛电影院 | 黑人粗长大战亚洲女2021国产精品成人免费视频 | 久久精品国产亚洲AV麻豆~| 久久九九亚洲精品| 久久九九亚洲精品| 婷婷亚洲综合五月天小说| 久久久久亚洲AV无码专区首| 亚洲精品国产成人99久久| 亚洲人成影院在线| 97亚洲熟妇自偷自拍另类图片 | 自拍偷自拍亚洲精品播放| 亚洲高清成人一区二区三区| 国产精品亚洲精品日韩电影| 亚洲 国产 图片| 亚洲五月午夜免费在线视频| 亚洲中文字幕无码久久精品1| 亚洲综合AV在线在线播放| 亚洲精品成人网站在线观看| 亚洲不卡中文字幕无码| 久久精品亚洲综合专区| 久久青青草原亚洲av无码app | 亚洲久悠悠色悠在线播放| 中国亚洲呦女专区| 亚洲AV成人精品一区二区三区| 香蕉视频亚洲一级| 亚洲一区二区三区免费| 亚洲精品国产成人片| 亚洲国产综合专区电影在线| 亚洲黄色免费电影| 国产成人精品日本亚洲网址 | 亚洲国语精品自产拍在线观看| 亚洲视频在线免费看| 国产色在线|亚洲|