成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

讓人心疼的Java虛引用!

開發 后端
在Java的世界里,對象的存在層次,也有三六九等,充滿了階層之間的嘲弄。強軟弱虛各種引用,對于熟悉Java的同學一定不會感到陌生,它們隨著等級的降低,越來越沒存在感。

[[405737]]

本文轉載自微信公眾號「小姐姐味道」,作者小姐姐養的狗 。轉載本文請聯系小姐姐味道公眾號。

在Java的世界里,對象的存在層次,也有三六九等,充滿了階層之間的嘲弄。強軟弱虛各種引用,對于熟悉Java的同學一定不會感到陌生,它們隨著等級的降低,越來越沒存在感。平常使用的對象,大多數就是強引用的;而軟引用和弱引用,則經常在一些堆內緩存框架中用到。

那虛引用呢?傳說中的幽靈引用,是不是就如同它的名字一樣,一無是處呢?

三種引用

首先,我們來回顧一下其他三種引用的類型和用途。

Strong references

當內存空間不足,系統撐不住了,JVM 就會拋出 OutOfMemoryError 錯誤。即使程序會異常終止,這種對象也不會被回收。這種引用屬于最普通最強硬的一種存在,只有在和 GC Roots 斷絕關系時,才會被消滅掉。

這種引用,你每天的編碼都在用。例如:new 一個普通的對象。

  1. Object obj = new Object() 

這種方式可能是有問題的。假如你的系統被大量用戶(User)訪問,你需要記錄這個 User 訪問的時間。可惜的是,User 對象里并沒有這個字段,所以我們決定將這些信息額外開辟一個空間進行存放。

Soft references

軟引用用于維護一些可有可無的對象。在內存足夠的時候,軟引用對象不會被回收,只有在內存不足時,系統則會回收軟引用對象,如果回收了軟引用對象之后仍然沒有足夠的內存,才會拋出內存溢出異常。

可以看到,這種特性非常適合用在緩存技術上。比如網頁緩存、圖片緩存等。

Guava 的 CacheBuilder,就提供了軟引用和弱引用的設置方式。在這種場景中,軟引用比強引用安全的多。

軟引用可以和一個引用隊列(ReferenceQueue)聯合使用,如果軟引用所引用的對象被垃圾回收,Java 虛擬機就會把這個軟引用加入到與之關聯的引用隊列中。

Weak references

弱引用對象相比較軟引用,要更加無用一些,它擁有更短的生命周期。

當 JVM 進行垃圾回收時,無論內存是否充足,都會回收被弱引用關聯的對象。弱引用擁有更短的生命周期,在 Java 中,用 java.lang.ref.WeakReference 類來表示。

怪異的虛引用

以上幾個引用級別都很好理解,但是虛引用是個例外。虛引用可以使用下面的代碼定義:

  1. Object  object = new Object(); 
  2. ReferenceQueue queue = new ReferenceQueue(); 
  3. // 虛引用,必須與一個引用隊列關聯 
  4. PhantomReference pr = new PhantomReference(object, queue); 

但是當你想取出其中的值時(get),得到的卻總是null。

  1. //JDK源碼    
  2. /** 
  3.      * Returns this reference object's referent.  Because the referent of a 
  4.      * phantom reference is always inaccessible, this method always returns 
  5.      * {@code null}. 
  6.      * 
  7.      * @return {@code null
  8.      */ 
  9.     public T get() { 
  10.         return null
  11.     } 

虛引用主要用來跟蹤對象被垃圾回收的活動。

當垃圾回收器準備回收一個對象時,如果發現它還有虛引用,就會在回收對象之前,把這個虛引用加入到與之關聯的引用隊列中。

程序如果發現某個虛引用已經被加入到引用隊列,那么就可以在所引用的對象的內存被回收之前采取必要的行動。

桃花源深處

在hotspot的jvm中,有一個叫做cleaner的類,其實就是虛引用典型的應用。可以看到Cleaner是直接簡單粗暴的繼承了PhantomReference,所以它本質上就是一個虛引用,只不過多了一些便捷的操作。

那么這個類是在什么地方用到的呢?大家手上應該都有jdk的源代碼,追蹤一下,發現最后竟然是DirectByteBuffer用到了它。

直接內存,一直是一個看起來非常高大上的名詞,基本上和高性能掛鉤,但也容易產生內存泄漏。由于直接內存,是屬于堆外內存的,所以垃圾回收的時候,就不能靠JVM的那一套垃圾回收算法進行清理。

事實上,由于DirectByteBuffer可能會被使用較長時間,熬過了年輕代的各種回收,就會進入老年代。這時候就比較麻煩了,這些引用對象,要在下一輪Old GC或者Full GC才能觸發,如果你的老年代空間較大,觸發回收的操作就需要等很久很久。問題是,在這段時間內,雖然這些堆外內存不再使用了,但它仍然占用著較大的物理空間,最后造成嚴重的浪費甚至崩潰。

對堆外內存不是很熟悉的同學,可以看我以前的一張圖。或者直接看這篇文章。通過-XX:MaxDirectMemorySize可以限制直接內存的使用上限。

《一圖解千愁,jvm內存從來沒有這么簡單過!》

那么這些堆外內存是如何進行回收的呢?這就是Cleaner的作用。Cleaner通過next和prev構造了一個典型的鏈表,但它本身是沒有任何邏輯的,因為它的清理邏輯都在thunk方法中。

  1. cleaner = Cleaner.create(this, new Deallocator(base, size, cap)); 
  2.  
  3. public void clean() { 
  4.         if (remove(this)) { 
  5.             try { 
  6.                 this.thunk.run(); 

也就是Deallocator = De allocator。其中,傳入的base,就是靠unsafe類申請的堆外內存地址引用(僅僅是個地址),有了引用和容量,其實我們就能夠在回收的時候定位到真正的堆外內存塊。就像Deallocator做的一樣。

  1. public void run() { 
  2.   if (address == 0) { 
  3.     // Paranoia 
  4.     return
  5.   } 
  6.   unsafe.freeMemory(address); 
  7.   address = 0; 
  8.   Bits.unreserveMemory(size, capacity); 

機制上沒什么問題,關鍵要看它們是怎么聯系起來的。這種問題,當然是要靠其他線程完成,這里就是ReferenceHandler。很熟悉的名字,你每次使用jstack命令導出堆棧,都會看到它。

  1. Thread handler = new ReferenceHandler(tg, "Reference Handler"); 
  2. /* If there were a special system-only priority greater than 
  3. * MAX_PRIORITY, it would be used here 
  4. */ 
  5. handler.setPriority(Thread.MAX_PRIORITY); 
  6. handler.setDaemon(true); 
  7. handler.start(); 

真正去工作的方法,是tryHandlePending,然后在這里,調用Cleaner的clean方法,進而調用真正的清理方法,釋放堆外內存。它會從虛引用注冊的隊列里,取出新的對象,然后判斷是不是Cleaner類型,如果是,就進行一次清理。

End

這就是虛引用。它存在的唯一目的,就是在回收的時候,能夠被感知到,以便進行更深層次的清理。在commons-io包的FileCleaningTracker類中,同樣有繼承了虛引用的Tracker類,用來跟蹤后續文件的一些清理工作。這個沒存在感的小小虛引用,默默的承擔起最后一道防線,是系統正常運行的有效保證。

不要小看它,它無處不在。因為你的每一個JVM進程,都跑著一個叫做Reference Handler的線程呢。

作者簡介:小姐姐味道 (xjjdog),一個不允許程序員走彎路的公眾號。聚焦基礎架構和Linux。十年架構,日百億流量,與你探討高并發世界,給你不一樣的味道。我的個人微信xjjdog0,歡迎添加好友,進一步交流。

 

責任編輯:武曉燕 來源: 小姐姐味道
相關推薦

2020-12-02 09:01:40

Java基礎

2009-06-19 16:19:23

Java對象引用

2012-05-09 13:36:30

WP7手機

2013-02-21 14:20:47

2021-10-18 15:50:49

Android強引用軟引用

2010-03-09 16:18:25

ArcGIS Expl

2022-01-17 10:18:33

騰訊末位淘汰制員工

2009-10-09 16:25:00

CCNA考試個人心得CCNA

2020-02-26 21:57:09

Lambdajava8方法引用

2024-05-20 08:58:13

Java引用類型垃圾回收器

2009-06-08 10:39:48

騰訊網友魔獸停服

2015-09-21 09:26:15

2017-04-24 18:39:24

人工智能

2011-05-25 09:49:35

項目

2011-11-04 16:44:45

iPhone應用

2023-09-02 20:05:07

GNOME 45

2010-01-18 17:38:54

C++虛函數表

2023-03-30 07:55:02

2020-08-03 12:26:22

數據透視函數公式

2016-10-20 09:32:30

Linux 4.9功能內核
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 精品视频一区二区三区在线观看 | 国产成人精品午夜视频免费 | 在线亚州| 婷婷99| 91在线视频观看 | 免费黄色大片 | 污污免费网站 | 久久久久久国产精品三区 | 日本视频在线播放 | 久久精品视频网站 | 久久成人免费 | 国产免国产免费 | 国产精品久久午夜夜伦鲁鲁 | 成人免费高清 | 日韩精品一区二区三区视频播放 | 欧美日韩不卡 | a久久 | 亚洲国产二区 | 电影在线 | 中文字幕成人av | xxx.在线观看 | 日韩视频免费 | 97av在线 | 成人免费高清 | 成人久久久 | 欧美老妇交乱视频 | 91精品久久久久久久久久 | 精品欧美一区免费观看α√ | 亚洲一区中文字幕在线观看 | 中文字幕一区在线观看视频 | 久久久久久久久久久一区二区 | 酒色成人网 | 天天夜夜操| 精品国产一区二区三区免费 | 久久精品国产久精国产 | 成人免费黄视频 | 久久久精品日本 | 亚洲精品久久久久久久久久久 | 在线免费观看视频黄 | 超碰97人人人人人蜜桃 | 日韩欧美三区 |