成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

怎么理解java的垃圾收集器

本篇內(nèi)容主要講解“怎么理解java的垃圾收集器”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“怎么理解java的垃圾收集器”吧!

創(chuàng)新互聯(lián)堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:網(wǎng)站設(shè)計(jì)、成都網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時(shí)代的吐魯番網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!

初識引用

對于剛接觸 Java 的 C++ 程序員而言,理解棧和堆的關(guān)系可能很不習(xí)慣。在 C++ 中,可以使用 new  操作符在堆上創(chuàng)建對象,或者使用自動(dòng)分配在棧上創(chuàng)建對象。下面的 C++ 語句是合法的,但是 Java 編譯器卻拒絕這么寫代碼,會(huì)出現(xiàn) syntax error  編譯錯(cuò)誤。

Integer foo = Integer(1);

Java 和 C 不一樣,Java 中會(huì)把對象都放在堆上,需要 new  操作符來創(chuàng)建對象。本地變量存儲在棧中,它們持有一個(gè)指向堆中對象的引用(指針)。下面是一個(gè) Java 方法,該方法具有一個(gè) Integer 變量,該變量從  String 解析值

public static void foo(String bar){     Integer baz = new Integer(bar); }

這段代碼我們使用堆棧分配圖可以看一下它們的關(guān)系

怎么理解java的垃圾收集器

首先先來看一下 foo() 方法,這一行代碼分配了一個(gè)新的 Integer 對象,JVM 嘗試在堆空間中開辟一塊內(nèi)存空間。如果允許分配的話,就會(huì)調(diào)用  Integer 的構(gòu)造方法把 String 字符串轉(zhuǎn)換為 Integer 對象。JVM 將指向該對象的指針存儲在變量 baz 中。

上面這種情況是我們樂意看到的情況,畢竟我們不想在編寫代碼的時(shí)候遇到阻礙,但是這種情況是不可能出現(xiàn)的,當(dāng)堆空間無法為 bar 和 baz  開辟內(nèi)存空間時(shí),就會(huì)出現(xiàn) OutOfMemoryError,然后就會(huì)調(diào)用垃圾收集器(garbage collector)  來嘗試騰出內(nèi)存空間。這中間涉及到一個(gè)問題,垃圾收集器會(huì)回收哪些對象?

垃圾收集器

Java 給你提供了一個(gè) new 操作符來為堆中的對象開辟內(nèi)存空間,但它沒有提供 delete 操作符來釋放對象空間。當(dāng) foo() 方法返回時(shí),如果變量  baz 超過最大內(nèi)存,但它所指向的對象仍然還在堆中。如果沒有垃圾回收器的話,那么程序就會(huì)拋出 OutOfMemoryError 錯(cuò)誤。然而 Java  不會(huì),它會(huì)提供垃圾收集器來釋放不再引用的對象。

當(dāng)程序嘗試創(chuàng)建新對象并且堆中沒有足夠的空間時(shí),垃圾收集器就開始工作。當(dāng)收集器訪問堆時(shí),請求線程被掛起,試圖查找程序不再主動(dòng)使用的對象,并回收它們的空間。如果垃圾收集器無法釋放足夠的內(nèi)存空間,并且JVM  無法擴(kuò)展堆,則會(huì)出現(xiàn) OutOfMemoryError,你的應(yīng)用程序通常在這之后崩潰。還有一種情況是 StackOverflowError  ,它出現(xiàn)的原因是因?yàn)榫€程請求的棧深度要大于虛擬機(jī)所允許的深度時(shí)出現(xiàn)的錯(cuò)誤。

標(biāo)記 - 清除算法

Java 能永久不衰的一個(gè)原因就是因?yàn)槔占?。許多人認(rèn)為 JVM  會(huì)為每個(gè)對象保留一個(gè)引用計(jì)數(shù),當(dāng)每次引用對象的時(shí)候,引用計(jì)數(shù)器的值就 + 1,當(dāng)引用失效的時(shí)候,引用計(jì)數(shù)器的值就 - 1。而垃圾收集器只會(huì)回收引用計(jì)數(shù)器的值為  0 的情況。這其實(shí)是 引用計(jì)數(shù)法(Reference Counting) 的收集方式。但是這種方式無法解決對象之間相互引用的問題,如下

class A{   public B b;  } class B{   public A a; } public class Main{     public static void main(String[] args){     A a = new A();     B b = new B();     a.b=b;     b.a=a;     } }

然而實(shí)際上,JVM 使用一種叫做  標(biāo)記-清除(Mark-Sweep)的算法,標(biāo)記清除垃圾回收背后的想法很簡單:程序無法到達(dá)的每個(gè)對象都是垃圾,可以進(jìn)行回收。

標(biāo)記-清除收集具有如下幾個(gè)階段

  • 階段一:標(biāo)記

垃圾收集器會(huì)從 根(root)  引用開始,標(biāo)記它到達(dá)的所有對象。如果用老師給學(xué)生判斷卷子來比喻,這就相當(dāng)于是給試卷上的全部答案判斷正確還是錯(cuò)誤的過程。

怎么理解java的垃圾收集器

  • 階段二:清理

在第一階段中所有可回收的的內(nèi)容都能夠被垃圾收集器進(jìn)行回收。如果一個(gè)對象被判定為是可以回收的對象,那么這個(gè)對象就被放在一個(gè) finalization  queue(回收隊(duì)列)中,并在稍后會(huì)由一個(gè)虛擬機(jī)自動(dòng)建立的、低優(yōu)先級的 finalizer 線程去執(zhí)行它。

怎么理解java的垃圾收集器

  • 階段三:整理(可選)

一些收集器有第三個(gè)步驟,整理。在這個(gè)步驟中,GC  將對象移動(dòng)到垃圾收集器回收完對象后所留下的自由空間中。這么做可以防止堆碎片化,防止大對象在堆中由于堆空間的不連續(xù)性而無法分配的情況。

怎么理解java的垃圾收集器

所以上面的過程中就涉及到一個(gè)根節(jié)點(diǎn)(GC Roots) 來判斷是否存在需要回收的對象。這個(gè)算法的基本思想就是通過一系列的 GC Roots  作為起始點(diǎn),從這些節(jié)點(diǎn)向下搜索,搜索所走過的路徑稱為 引用鏈(Reference Chain),當(dāng)一個(gè)對象到 GC Roots  之間沒有任何引用鏈相連的話,則證明此對象不可用。引用鏈上的任何一個(gè)能夠被訪問的對象都是強(qiáng)引用 對象,垃圾收集器不會(huì)回收強(qiáng)引用對象。

因此,返回到 foo() 方法中,僅在執(zhí)行方法時(shí),參數(shù) bar 和局部變量 baz  才是強(qiáng)引用。一旦方法執(zhí)行完成,它們都超過了作用域的時(shí)候,它們引用的對象都會(huì)進(jìn)行垃圾回收。

下面來考慮一個(gè)例子

LinkedList foo = new LinkedList(); foo.add(new Integer(111));

變量 foo 是一個(gè)強(qiáng)引用,它指向一個(gè) LinkedList 對象。LinkedList(JDK.18)  是一個(gè)鏈表的數(shù)據(jù)結(jié)構(gòu),每一個(gè)元素都會(huì)指向前驅(qū)元素,每個(gè)元素都有其后繼元素。

怎么理解java的垃圾收集器

當(dāng)我們調(diào)用add() 方法時(shí),我們會(huì)增加一個(gè)新的鏈表元素,并且該鏈表元素指向值為 111 的 Integer 實(shí)例。這是一連串的強(qiáng)引用,也就是說,這個(gè)  Integer 的實(shí)例不符合垃圾收集條件。一旦 foo 對象超出了程序運(yùn)行的作用域,LinkedList  和其中的引用內(nèi)容都可以進(jìn)行收集,收集的

protected void finalize() throws Throwable {     // 清除對象 }

前提是沒有強(qiáng)引用關(guān)系。

Finalizers

C++  允許對象定義析構(gòu)函數(shù)方法:當(dāng)對象超出作用范圍或被明確刪除時(shí),會(huì)調(diào)用析構(gòu)函數(shù)來清理使用的資源。對于大多數(shù)對象來說,析構(gòu)函數(shù)能夠釋放使用 new 或者 malloc  函數(shù)分配的內(nèi)存。在Java中,垃圾收集器會(huì)為你自動(dòng)清除對象,分配內(nèi)存,因此不需要顯式析構(gòu)函數(shù)即可執(zhí)行此操作。這也是 Java 和 C++ 的一大區(qū)別。

然而,內(nèi)存并不是唯一需要被釋放的資源。考慮  FileOutputStream:當(dāng)你創(chuàng)建此對象的實(shí)例時(shí),它從操作系統(tǒng)分配文件句柄。如果你讓流的引用在關(guān)閉前超過了其作用范圍,該文件句柄會(huì)怎么樣?實(shí)際上,每個(gè)流都會(huì)有一個(gè)  finalizer 方法,這個(gè)方法是垃圾回收器在回收之前由 JVM 調(diào)用的方法。對于 FileOutputStream 來說,finalizer  方法會(huì)關(guān)閉流,釋放文件句柄給操作系統(tǒng),然后清除緩沖區(qū),確保數(shù)據(jù)能夠?qū)懭氪疟P。

任何對象都具有 finalizer 方法,你要做的就是聲明 finalize() 方法。如下

protected void finalize() throws Throwable {     // 清除對象 }

雖然 finalizers 的 finalize()  方法是一種好的清除方式,但是這種方法產(chǎn)生的負(fù)面影響非常大,你不應(yīng)該依靠這個(gè)方法來做任何垃圾回收工作。因?yàn)?finalize  方法的運(yùn)行開銷比較大,不確定性強(qiáng),無法保證各個(gè)對象的調(diào)用順序。finalize 能做的任何事情,可以使用 try-finally  或者其他方式來做,甚至做的更好。

對象的生命周期

綜上所述,可以通過下面的流程來對對象的生命周期做一個(gè)總結(jié)

怎么理解java的垃圾收集器

對象被創(chuàng)建并初始化,對象在運(yùn)行時(shí)被使用,然后離開對象的作用域,對象會(huì)變成不可達(dá)并會(huì)被垃圾收集器回收。圖中用紅色標(biāo)明的區(qū)域表示對象處于強(qiáng)可達(dá)階段。

JDK1.2 介紹了 java.lang.ref 包,對象的生命周期有四個(gè)階段:?強(qiáng)可達(dá)?(Strongly  Reachable?)、軟可達(dá)(Soft Reachable?)、弱可達(dá)(Weak Reachable?)、 幻象可達(dá)(Phantom  Reachable?)。

怎么理解java的垃圾收集器

如果只討論符合垃圾回收條件的對象,那么只有三種:軟可達(dá)、弱可達(dá)和幻象可達(dá)。

  • 軟可達(dá):軟可達(dá)就是?我們只能通過軟引用?才能訪問的狀態(tài),軟可達(dá)的對象是由 SoftReference  引用的對象,并且沒有強(qiáng)引用的對象。軟引用是用來描述一些還有用但是非必須的對象。垃圾收集器會(huì)盡可能長時(shí)間的保留軟引用的對象,但是會(huì)在發(fā)生  OutOfMemoryError 之前,回收軟引用的對象。如果回收完軟引用的對象,內(nèi)存還是不夠分配的話,就會(huì)直接拋出 OutOfMemoryError。

  • 弱可達(dá):弱可達(dá)的對象是 WeakReference 引用的對象。垃圾收集器可以隨時(shí)收集弱引用的對象,不會(huì)嘗試保留軟引用的對象。

  • 幻象可達(dá):幻象可達(dá)是由 PhantomReference 引用的對象,幻象可達(dá)就是沒有強(qiáng)、軟、弱引用進(jìn)行關(guān)聯(lián),并且已經(jīng)被 finalize  過了,只有幻象引用指向這個(gè)對象的時(shí)候。

除此之外,還有強(qiáng)可達(dá)和不可達(dá)的兩種可達(dá)性判斷條件

  • 強(qiáng)可達(dá):就是一個(gè)對象剛被創(chuàng)建、初始化、使用中的對象都是處于強(qiáng)可達(dá)的狀態(tài)

  • 不可達(dá)(unreachable):處于不可達(dá)的對象就意味著對象可以被清除了。

下面是一個(gè)不同可達(dá)性狀態(tài)的轉(zhuǎn)換圖

怎么理解java的垃圾收集器

判斷可達(dá)性條件,也是 JVM 垃圾收集器決定如何處理對象的一部分考慮因素。

所有的對象可達(dá)性引用都是 java.lang.ref.Reference 的子類,它里面有一個(gè)get()  方法,返回引用對象。如果已通過程序或垃圾收集器清除了此引用對象,則此方法返回 null  。也就是說,除了幻象引用外,軟引用和弱引用都是可以得到對象的。而且這些對象可以人為拯救,變?yōu)閺?qiáng)引用,例如把 this  關(guān)鍵字賦值給對象,只要重新和引用鏈上的任意一個(gè)對象建立關(guān)聯(lián)即可。

ReferenceQueue

引用隊(duì)列又稱為 ReferenceQueue,它位于 java.lang.ref  包下。我們在?建各種引用(軟引用,弱引用,幻象引用)并關(guān)聯(lián)到響應(yīng)對象?時(shí),可以選擇是否需要關(guān)聯(lián)引用隊(duì)列。JVM  會(huì)在特定的時(shí)機(jī)將引用入隊(duì)到隊(duì)列中,程序可以通過判斷引用隊(duì)列中是否已經(jīng)加入引用,來了解被引用的對象是否被GC回收。

Reference

java.lang.ref.Reference 為軟(soft)引用、弱(weak)引用、虛(phantom)引用的父類。因?yàn)? Reference 對象和垃圾回收密切配合實(shí)現(xiàn),該類可能不能被直接子類化。

到此,相信大家對“怎么理解java的垃圾收集器”有了更深的了解,不妨來實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

當(dāng)前文章:怎么理解java的垃圾收集器
網(wǎng)頁路徑:http://jinyejixie.com/article10/ijdjdo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供域名注冊、響應(yīng)式網(wǎng)站、自適應(yīng)網(wǎng)站、網(wǎng)站改版、網(wǎng)站營銷定制網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站網(wǎng)頁設(shè)計(jì)
永新县| 南澳县| 邓州市| 永新县| 清水河县| 始兴县| 常山县| 台北市| 上高县| 温宿县| 宜章县| 沙河市| 宜丰县| 南漳县| 陇川县| 耿马| 峡江县| 曲麻莱县| 双峰县| 会东县| 广平县| 苗栗县| 扎鲁特旗| 洛川县| 禄丰县| 略阳县| 民乐县| 麦盖提县| 家居| 莎车县| 小金县| 枝江市| 尤溪县| 汉沽区| 武邑县| 林周县| 闽侯县| 西青区| 大新县| 商都县| 扶沟县|