程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 深化了解Java中的弱援用

深化了解Java中的弱援用

編輯:關於JAVA

深化了解Java中的弱援用。本站提示廣大學習愛好者:(深化了解Java中的弱援用)文章只能為提供參考,不一定能成為您想要的結果。以下是深化了解Java中的弱援用正文


不久之前,我面試了一些求職Java初級開發工程師的應聘者。我經常會面試他們說,“你能給我引見一些Java中得弱援用嗎?”,假如面試者這樣說,“嗯,是不是渣滓回收有關的?”,我就會根本稱心了,我並不等待答復是一篇诘究本末的論文描繪。

但是適得其反,我很吃驚的發現,在將近20多個有著均勻5年開發經歷和高學歷背景的應聘者中,竟然只要兩團體知道弱援用的存在,但是在這兩團體之中只要一團體真正理解這方面的知識。在面試進程中,我還嘗試提示一些東西,來看看有沒有人忽然說一聲“原來是這個啊”,後果很是讓我絕望。我開端困惑,為什麼這塊的知識如此不被注重,畢竟弱援用是一個很有用處的特性,況且這個特性曾經在7年前 Java 1.2發布時便引入了。

好吧,這裡我不等待你看完本文之後成為一個弱援用方面的專家,但是我以為至多你應該理解什麼是弱援用,如何運用它們,並且什麼場景運用。既然它們是一些不知名的概念,我復雜就著後面的三個問題來闡明一下。

強援用(Strong Reference)

強援用就是我們常常運用的援用,其寫法如下:


StringBuffer buffer = new StringBuffer();

下面創立了一個StringBuffer對象,並將這個對象的(強)援用存到變量buffer中。是的,就是這個小兒科的操作(請原諒我這樣的說法)。強援用最重要的就是它可以讓援用變得強(Strong),這就決議了它和渣滓回收器的交互。詳細來說,假如一個對象經過一串強援用鏈接可抵達(Strongly reachable),它是不會被回收的。假如你不想讓你正在運用的對象被回收,這就正是你所需求的。

但是強援用如此之強

在一個順序裡,將一個類設置成不可被擴展是有點不太罕見的,當然這個完全可以經過類標志成final完成。或許也可以愈加復雜一些,就是經過外部包括了未知數量詳細完成的工廠辦法前往一個接口(Interface)。舉個例子,我們想要運用一個叫做Widget的類,但是這個類不能被承繼,所以無法添加新的功用。

但是我們假如想追蹤Widget對象的額定信息,我們該怎樣辦? 假定我們需求記載每個對象的序列號,但是由於Widget類並不包括這個屬性,而且也不能擴展招致我們也不能添加這個屬性。其實一點問題也沒有,HashMap完全可以處理上述的問題。


serialNumberMap.put(widget, widgetSerialNumber);

這外表看上去沒有問題,但是widget對象的強援用很有能夠會引提問題。我們可以確信當一個widget序列號不需求時,我們應該將這個條目從map中移除。假如我們沒有移除的話,能夠會招致內存洩露,亦或許我們手動移除時刪除了我們正在運用的widgets,會招致無效數據的喪失。其實這些問題很相似,這就是沒有渣滓回收機制的言語管理內存時常遇到的問題。但是我們不必去擔憂這個問題,由於我們運用的時具有渣滓回收機制的Java言語。

另一個強援用能夠帶來的問題就是緩存,尤其是像圖片這樣的大文件的緩存。假定你有一個順序需求處置用戶提供的圖片,通常的做法就是做圖片數據緩存,由於從磁盤加載圖片代價很大,並且同時我們也想防止在內存中同時存在兩份一樣的圖片數據。

緩存被設計的目的就是防止我們去再次加載哪些不需求的文件。你會很快發如今緩存中會不斷包括一個到曾經指向內存中圖片數據的援用。運用強援用會強迫圖片數據留在內存,這就需求你來決議什麼時分圖片數據不需求並且手動從緩存中移除,進而可以讓渣滓回收器回收。因而你再一次被強迫做渣滓回收器該做的任務,並且人為決議是該清算到哪一個對象。

弱援用(Weak Reference)

弱援用復雜來說就是將對象留在內存的才能不是那麼強的援用。運用WeakReference,渣滓回收器會幫你來決議援用的對象何時回收並且將對象從內存移除。創立弱援用如下:

eakReference<Widget> weakWidget = new WeakReference<Widget>(widget);

運用weakWidget.get()就可以失掉真實的Widget對象,由於弱援用不能阻撓渣滓回收器對其回收,你會發現(當沒有任何強援用到widget對象時)運用get時忽然前往null。

處理上述的widget序列數記載的問題,最復雜的方法就是運用Java內置的WeakHashMap類。WeakHashMap和HashMap簡直一樣,獨一的區別就是它的鍵(不是值!!!)運用WeakReference援用。當WeakHashMap的鍵標志為渣滓的時分,這個鍵對應的條目就會自動被移除。這就防止了下面不需求的Widget對象手動刪除的問題。運用WeakHashMap可以很便捷地轉為HashMap或許Map。

援用隊列(Reference Queue)

一旦弱援用對象開端前往null,該弱援用指向的對象就被標志成了渣滓。而這個弱援用對象(非其指向的對象)就沒有什麼用了。通常這時分需求停止一些清算任務。比方WeakHashMap會在這時分移除沒用的條目來防止保管有限制增長的沒有意義的弱援用。

援用隊列可以很容易地完成跟蹤不需求的援用。當你在結構WeakReference時傳入一個ReferenceQueue對象,當該援用指向的對象被標志為渣滓的時分,這個援用對象會自動地參加到援用隊列外面。接上去,你就可以在固定的周期,處置傳入的援用隊列,比方做一些清算任務來處置這些沒有用的援用對象。

四種援用

Java中實踐上有四種強度不同的援用,從強到弱它們辨別是,強援用,軟援用,弱援用和虛援用。下面局部引見了強援用和弱援用,上面引見剩下的兩個,軟援用和虛援用。

軟援用(Soft Reference)

軟援用根本上和弱援用差不多,只是相比弱援用,它阻止渣滓回收期回收其指向的對象的才能強一些。假如一個對象是弱援用可抵達,那麼這個對象會被渣滓回收器接上去的回收周期銷毀。但是假如是軟援用可以抵達,那麼這個對象會停留在內存更時間上長一些。當內存缺乏時渣滓回收器才會回收這些軟援用可抵達的對象。

由於軟援用可抵達的對象比弱援用可到達的對象滯留內存時間會長一些,我們可以應用這個特性來做緩存。這樣的話,你就可以節省了很多事情,渣滓回收器會關懷以後哪種可抵達類型以及內存的耗費水平來停止處置。

虛援用 (Phantom Reference)

與軟援用,弱援用不同,虛援用指向的對象非常軟弱,我們不可以經過get辦法來失掉其指向的對象。它的獨一作用就是當其指向的對象被回收之後,自己被參加到援用隊列,用作記載該援用指向的對象已被銷毀。

當弱援用的指向對象變得弱援用可抵達,該弱援用就會參加到援用隊列。這一操作發作在對象析構或許渣滓回收真正發作之前。實際上,這個行將被回收的對象是可以在一個不契合標准的析構辦法外面重新復生。但是這個弱援用會銷毀。虛援用只要在其指向的對象從內存中移除掉之後才會參加到援用隊列中。其get辦法不斷前往null就是為了阻止其指向的簡直被銷毀的對象重新復生。

虛援用運用場景次要由兩個。它允許你知道詳細何時其援用的對象從內存中移除。而實踐上這是Java中獨一的方式。這一點尤其表如今處置相似圖片的大文件的狀況。當你確定一個圖片數據對象應該被回收,你可以應用虛援用來判別這個對象回收之後在持續加載下一張圖片。這樣可以盡能夠地防止可怕的內存溢出錯誤。

第二點,虛援用可以防止很多析構時的問題。finalize辦法可以經過創立強援用指向快被銷毀的對象來讓這些對象重新復生。但是,一個重寫了finalize辦法的對象假如想要被回收掉,需求閱歷兩個獨自的渣滓搜集周期。在第一個周期中,某個對象被標志為可回收,進而才干停止析構。但是由於在析構進程中仍有微弱的能夠這個對象會重新復生。這種狀況下,在這個對象真實銷毀之前,渣滓回收器需求再次運轉。由於析構能夠並不是很及時,所以在調用對象的析構之前,需求閱歷數量不確定的渣滓搜集周期。這就意味著在真正清算掉這個對象的時分能夠發作很大的延遲。這就是為什麼當大局部堆被標志成渣滓時還是會呈現煩人的內存溢出錯誤。

運用虛援用,上述狀況將引刃而解,當一個虛援用參加到援用隊列時,你相對沒有方法失掉一個銷毀了的對象。由於這時分,對象曾經從內存中銷毀了。由於虛援用不能被用作讓其指向的對象重生,所以其對象會在渣滓回收的第一個周期就將被清算掉。

不言而喻,finalize辦法不建議被重寫。由於虛援用分明地平安高效,去掉finalize辦法可以虛擬機變得分明復雜。當然你也可以去重寫這個辦法來完成更多。這完全看團體選擇。

總結

我想看到這裡,很多人開端發怨言了,為什麼你要講一個過來十年的老古董API呢,好吧,以我的經歷看,很多的Java順序員並不是很理解這個知識,我以為有一些深化的了解是很必要的,同時我希望大家能從本文中播種一些東西。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved