java虛引用作用_深入理解Java中的引用(二)——強軟弱虛引用

深入理解Java中的引用(二)——強軟弱虛引用

在上一篇文章中介紹了Java的Reference類,本篇文章介紹他的四個子類:強引用、軟引用、弱引用、虛引用。

強引用(StrongReference)

強引用是我們在代碼中最普通的引用。示例代碼如下:

Object o = new Object(); // 強引用

在JVM的GC算法中,如果一個對象具有強引用,那么JVM寧可拋出Out of Memory錯誤,垃圾回收器也不會去回收這個對象。

當在代碼里顯示的寫o = null,或者該對象的引用作用域是在一個函數里,代碼如下,當線程調用完test,就會退出方法棧,引用不存在,垃圾回收器才會在某個時刻回收Object對象。

public void test(){

Object o = new Object(); // 強引用

}

軟引用(SoftReference)

如果一個對象有一個軟引用,那么在內存足夠的情況下,該對象就不會被垃圾回收器回收。網上有很多資料說軟引用只會在內存空間不夠用的情況下對象才會被回收。 那么什么時候才是內存不夠用呢?

首先看一下SoftReference類的源碼可以看到有兩個字段。這兩個字段的作用已經標注,這與JVM GC有什么關系呢?

/**

* 記錄最近一次被GC的時間。

*/

static private long clock;

/**

* 每次調用get方法的時候更新

* 記錄當前Reference最近一次被訪問的時間

*/

private long timestamp;

一起看一下HotSpot的源碼,對于軟引用的回收策略見下面should_clear_reference函數。

// The oop passed in is the SoftReference object, and not

// the object the SoftReference points to.

bool LRUMaxHeapPolicy::should_clear_reference(oop p,

jlong timestamp_clock) {

jlong interval = timestamp_clock - java_lang_ref_SoftReference::timestamp(p);

assert(interval >= 0, "Sanity check");

// The interval will be zero if the ref was accessed since the last scavenge/gc.

if(interval <= _max_interval) {

return false;

}

return true;

}

上述代碼中interval表示當前引用存活了多久。他的值就是對應上述java代碼中的clock與timestamp相減。interval與_max_interval比較,如果大于 _max_interval,那么就和弱引用一樣處理,如果小于就當做強引用處理。_max_interval的賦值函數如下:

// Capture state (of-the-VM) information needed to evaluate the policy

void LRUMaxHeapPolicy::setup() {

size_t max_heap = MaxHeapSize;

max_heap -= Universe::get_heap_used_at_last_gc();

max_heap /= M;

_max_interval = max_heap * SoftRefLRUPolicyMSPerMB;

assert(_max_interval >= 0,"Sanity check");

}

通過源碼可見首先是max_heap減去上次GC之后剩余堆大小,如果上次GC之后還有很多剩余空間,說明內存空間不夠用了,那么max_heap的值就越小,相應_max_interval也越小,軟引用就越可能被回收。

軟引用的一個作用是實現內存敏感的高速緩存。比如瀏覽器的后退按鈕,

(1)如果網頁瀏覽結束就進行內容的回收,則按后退查看前面瀏覽過的頁面時,需要重新構建。

(2)如果將瀏覽過的網頁存儲到內存中會造成內存的大量浪費,甚至會造成內存溢出。

通過軟引用可以解決該問題

Browser prev = new Browser(); // 獲取頁面進行瀏覽

SoftReference sr = new SoftReference(prev); // 瀏覽完畢后置為軟引用

if(sr.get()!=null){

rev = (Browser) sr.get(); // 還沒有被回收器回收,直接獲取

}else{

prev = new Browser(); // 由于內存吃緊,所以對軟引用的對象回收了

sr = new SoftReference(prev); // 重新構建

}

弱引用(WeakReference)

只具有弱引用的對象生命周期更短。當垃圾回收器發現了只有弱引用的對象時候,無論內存空間是否足夠,都會被GC回收。當你偶爾需要引用某個對象,隨時能獲取該對象,但是不想介入該對象的生命周期的時候,就可以使用弱引用, 因為弱引用不會對對象的垃圾回收判斷產生附加的影響。

當弱引用綁定的對象被垃圾回收的時候,JVM會把這個弱引用加入到相關聯的ReferenceQueue中。

這里拋出兩個問題:

(1)弱引用什么時候會被加入到ReferenceQueue中,由什么決定的呢?

(2)如果綁定的對象GC之后存活了下來,弱引用怎么知道這個對象的新地址呢?

第一種情況,GC掃描到只存在弱引用的時候就會把它放到鏈表里。還有第二種情況:一個對象既有強引用又有弱引用的情況

下面通過圖片來解釋上面兩個問題:

e279b8b492aa

image.png

上圖表示C同時存在兩個引用:強引用A和弱引用B。

第一種情況:GC先掃描到A

這種情況下GC同時會掃描到C,A和C都會搬到Survivor區。然后掃描到B,發現B引用的C搬到到了新的Survivor,這個時候就把B也搬到Survivor,并把C的新地址更新到B,結果如下:

e279b8b492aa

image.png

第二種情況:GC先掃描到B

GC還是會先把B放到ReferenceQueue中,由于C還是存活的,所以B會被搬到Survivor中。然后掃描到A,A和C都會搬到Survivor中,GC結束的時候B所指向的對象就不對了,如下圖所示

e279b8b492aa

image.png

該情況下會重新遍歷ReferenceQueue,發現綁定的對象依然存活,C‘ 的指針是指向C的,于是就把B再指向C就可以了,同時因為C依然存活,把B從ReferenceQueue中移除。新的地址空間如下圖所示:

e279b8b492aa

image.png

具體過程可以查看海納知乎專欄。

虛引用(PhantomReference)

虛引用不會對對象的垃圾回收有任何附加影響,他與軟引用和弱引用的一個區別在于:虛引用必須和引用隊列 (ReferenceQueue)聯合使用。查看他的構造方法可以看到必須與一個ReferenceQueue綁定,而且他的get方法返回的一直是null

public T get() {

return null;

}

public PhantomReference(T referent, ReferenceQueue super T> q) {

super(referent, q);

}

虛引用主要用在跟蹤對象垃圾回收的狀態。具體應用會在在下一節講到DirectByteBuffer 與ThreadLoal回收的時候詳細分析。

總結

關于強引用、軟引用、弱引用與虛引用在垃圾回收時的區別可以用下圖表示:

e279b8b492aa

image.png

下圖總結了四種引用在其他方面的區別:

e279b8b492aa

image.png

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/538414.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/538414.shtml
英文地址,請注明出處:http://en.pswp.cn/news/538414.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

SQL查詢表的列名

SELECT COLUMN_NAME FROM DBA_TAB_COLUMNS WHERE TABLE_NAME DT4_JOB_CHECK_MATRIX;SELECT COLUMN_NAME FROM ALL_TAB_COLUMNS WHERE TABLE_NAME DT4_JOB_CHECK_MATRIX;SELECT COLUMN_NAME FROM USER_TAB_COLUMNS WHERE TABLE_NAME DT4_JOB_CHECK_MATRIX;

java老鳥123怎么樣_java入門123——一個老鳥的java學習心得.doc

java入門123——一個老鳥的java學習心得java入門123——一個老鳥的java學習心得篇一&#xff1a;java初學者學習心得學習Java心得體會學習了一學期的Java課程,覺得是該總結自己的心得體會了。開始學習任何一門課(包括java)&#xff0c;興趣最重要。一直覺得自己在學計算機編程語…

ruby 爬蟲爬取拉鉤網職位信息,產生詞云報告

思路&#xff1a;1.獲取拉勾網搜索到職位的頁數 2.調用接口獲取職位id 3.根據職位id訪問頁面&#xff0c;匹配出關鍵字 url訪問采用unirest&#xff0c;由于拉鉤反爬蟲&#xff0c;短時間內頻繁訪問會被限制訪問&#xff0c;所以沒有采用多線程&#xff0c;而且每個頁面訪問時間…

評論語義分析 分詞 分類python_用python調用ICTCLAS50進行中文分詞

直接上源碼吧tokenizer類&#xff1a;#_*_encoding:utf-8_*_from ctypes import *class tokenizer:def __init__(self):self._stext[、,“,”,&#xff0c;,。,《,》,&#xff1a;,&#xff1b;,!,‘,’,?,&#xff1f;,&#xff01;,, ,] #枚舉標點符號包括空格self._stopwor…

java對日期Date類進行加減運算、年份加減,月份加減

JAVA處理日期時間常用方法&#xff1a; 1.Java.util.Calendar Calendar 類是一個抽象類&#xff0c;它為特定瞬間與一組諸如 YEAR、MONTH、DAY_OF_MONTH、HOUR 等 日歷字段之間的轉換提供了一些方法&#xff0c;并為操作日歷字段&#xff08;例如獲得下星期的日期&#xff09…

idle擴展插件_Python3.4學習筆記之 idle 清屏擴展插件用法分析

本文實例講述了Python3.4 idle 清屏擴展插件用法。分享給大家供大家參考&#xff0c;具體如下&#xff1a;python idle 清屏問題的解決&#xff0c;使用python idle都會遇到一個常見而又懊惱的問題——要怎么清屏?在stackoverflow看到這樣兩種答案&#xff1a;1.在shell中輸入…

內存堆和棧的區別

原文鏈接&#xff1a;http://www.cnblogs.com/lln7777/archive/2012/03/14/2396164.html -------------------------------------------------------------------------------- 在計算機領域&#xff0c;堆棧是一個不容忽視的概念&#xff0c;我們編寫的C語言程序基本上都要用…

MYSQL安裝和配置

Win10安裝MySQL5.7.22 解壓縮版&#xff08;手動配置 1.下載地址&#xff1a;https://dev.mysql.com/downloads/mysql/5.7.html#downloads 直接點擊下載項 下載后&#xff1a; 2.可以把解壓的內容隨便放到一個目錄&#xff0c;我的是如下目錄&#xff08;放到C盤的話&#xff0…

python刪除過期文件_python刪除過期文件的方法

本文實例講述了python刪除過期文件的方法。分享給大家供大家參考。具體實現方法如下&#xff1a;# remove all jpeg image files of an expired modification date mtime# you could also use creation date (ctime) or last access date (atime)# os.stat(filename) returns …

【很久之前的一篇老文章】一位程序員工作10年總結的13個忠告

展望未來&#xff0c;總結過去10年的程序員生涯&#xff0c;給程序員小弟弟小妹妹們的一些總結性忠告。 走過的路&#xff0c;回憶起來是那么曲折&#xff0c;把自己的一些心得體會分享給程序員兄弟姐妹們&#xff0c;雖然時代在變化&#xff0c;但是很可能你也會走我已經做過的…

apply()與call()的區別

一直都沒太明白apply()與call()的具體使用原理&#xff0c;今日閑來無事&#xff0c;決定好好研究一番。 JavaScript中的每一個Function對象都有一個apply()方法和一個call()方法&#xff0c;它們的語法分別為&#xff1a; /*apply()方法*/ function.apply(thisObj[, argArray]…

java代碼執行了兩次_Java中JComboBox的itemStateChanged事件執行兩次的解釋

今天做項目&#xff0c;用到了JComboBox&#xff0c;即下拉列表框。為了在被選中的項發生改變時獲得被選中的項&#xff0c;所以使用的ItemStateChanged事件&#xff0c;可是問題就來了&#xff0c;每次觸發該事件&#xff0c;它都執行兩次&#xff0c;屢試不爽。一開始以為是代…

python連接mongo_使用簡單的Python連接訪問MongoDB

繼續來聊MongoDB。MongoDB作為了一個數據庫產品軟件&#xff0c;除了服務器Server端進程(mongod)外&#xff0c;還提供了比較豐富的訪問連接接口。我們最常用的就是兩個類型&#xff0c;一個是原生mongo shell&#xff0c;另一個就是應用程序語言訪問接口。1、從Mongo Shell到應…

spring與mybatis三種整合方法

原文鏈接&#xff1a;http://www.cnblogs.com/wangmingshun/p/5674633.html ------------------------------------------------------------------------------------------------- 1、采用MapperScannerConfigurer&#xff0c;它將會查找類路徑下的映射器并自動將它們創建成…

js常用的2中排序方法:冒泡排序和快速排序

冒泡排序&#xff1a;例如9 4 5 6 8 3 2 7 10 1 首先&#xff1a;9和4比較 4放前 4 9 5 6 8 3 2 7 10 1 4和5比較 4不動 4 9 5 6 8 3 2 7 10 1 4和6比較 4不動 4 9 5 6 8 3 2 7 10 1 4和3比較 3放前 3 9 5 6 8 4 2 7 10 1 3和2比較 2放前 2 9 5 6 8…

java 注冊頁面正則式_Java使用正則表達式對注冊頁面進行驗證功能實現

本文給大家介紹java使用正則表達式對注冊頁面進行驗證的代碼&#xff0c;代碼如下所示&#xff1a;package regex;import java.util.Scanner;import java.util.regex.Matcher;import java.util.regex.Pattern;public class registered {public static void main(String[] args)…

python 編程效率_如何有效提升數據分析效率?五大Python技巧

如何有效提升數據分析效率&#xff1f;相信這是所有數據分析工作者都想解決的問題。本文整理了五大python技巧&#xff0c;分別是Pandas Profiling&#xff1b;使用 Cufflinks 和 Plotly 繪制 Pandas 數據&#xff1b;IPython 魔術命令&#xff1b;Jupyter 中的格式編排&#x…

please select a vaild python interpret

當 JetBrains PyCharm 2017.1.3 x64 遇到 please select a vaild python interpret 錯誤時&#xff1a; 進入PyCharm setting 選項&#xff0c;搜索 interpret

Grafana分析Nginx日志

配置Groub by -Terms時報錯&#xff0c;提示需要設置fielddatatrue&#xff0c;報錯內容大概如下&#xff1a; "Fielddata is disabled on text fields by default ... " 解決方法如下&#xff1a; https://www.elastic.co/guide/en/elasticsearch/reference/curren…

php curl json post請求_php post請求發送json對象數據參數

網頁中發送請求時&#xff0c;大部分情況都參數以鍵值組合發送數據的&#xff0c;而一些第三方如java開發的接口中需要發送post請求&#xff0c;請求參數為json類型。既然要發送json數據&#xff0c;首頁我們需要在請求頭中定義數據類型為json&#xff0c;告訴服務器客服端發送…