国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

與垃圾收集器(Garbage Collector)為伴

2019-11-18 15:21:52
字體:
來源:轉載
供稿:網友

垃圾收集器(Garbage Collector(GC))是一直伴隨著 java 程序員的最有爭議的問題之一。我們接受了獨立的收集器的原則,但是控制該收集器的迫切需要經常被證實是不可抗拒的。典型情況下,您用好了一個或多個資源,并指望它們會被回收。但它們并沒有被回收。一定出現了問題!IBM 為我們提供了一種強行執行 GC 的方法 ? 調用 System.gc(),那么使用這一調用就一定沒有問題,是這樣嗎? 錯。幾乎總是錯的。

GC 稱為“內存治理器”會更好,因為這是它真正做的事情。同 C/C++ 一樣,它根據應用程序的請求分配內存。但是與 C/C++ 不同的是,內存釋放是 GC 單獨執行的。因為內存治理的復雜性中 99% 與未使用內存的自動定位及釋放有關。一般我們提到“GC”就是指 Java 內存治理。

Java 虛擬機(Java virtual machine(JVM))有它自己的內存池。我們不使用一般的本地方法,如 malloc。當然,這個內存池只是從本機 OS 中分配的一大塊。Java 內存被稱作堆。當 Java 對象需要內存時,就從堆中進行內存分配。

通常,JVM 在被要求時才對內存進行分配。當且僅當內存分配發生錯誤(內存溢出)時才執行 GC。

是的,是的,我知道 Java 1.1.8 有“異步 GC”操作。在 IBM Java SDK 中,這個循環實際上從未被激活。因為性能的緣故,異步 GC 操作被配置成只有在您的應用程序確實什么事也不做的時候才會運行。即使您的應用程序靜止,也要經過相當長時間的超時,異步 GC 才會運行。在 Java 2 中已經沒有異步操作了。

因此,對于 IBM Java SDK 來說,GC 完全是一個同步操作,而且僅在內存分配發生錯誤時才發生。

GC 的工作方式
我們當然不會完整地討論這些內容;關于這一主題已經有整本專著問世了。我們只要討論基礎知識。

GC 通過掃描 JVM 里運行的所有線程的堆棧和寄存器來執行。假如它發現有些東西似乎是對 Java 堆內的引用,GC 將會繼續查下去。假如該引用確實是對對象的引用,那么 GC 將跟隨該對象內的所有引用。被引用的對象以及該對象所引用的所有對象都將被“標記”(或標志)。

顯然,只有在線程被中止的情況下它才能起作用,因此,GC 要停止 JVM 里的所有線程才能開始執行,當然,其中不包括它正在其上運行的那個線程。

標記階段結束時,GC 會掃描堆,并對照在標記階段標志的那些對象檢查堆里的所有對象。任何沒有被標記的對象都是沒有被任何線程引用的對象,因而,這些對象將會被回收并被放回到空閑池。

此處需要指出的重點是:

GC 是一個停止一切的操作。
GC 是一個同步操作。
GC 需要掃描每個線程的堆棧。
GC 需要掃描整個 Java 堆。
就 CPU 使用和時間而言,GC 操作代價高昂。這就是我們要盡可能減少它的執行的原因。雖然它效率極高,但在一個有許多線程并且堆的大小達多兆字節的環境中運行需要時間。

這解釋了相當常見的說法 -“我的對象在應該被回收的時候并沒有被回收”。它們符合被回收的條件;可是沒有必要運行 GC,所以它并沒有執行。

System.gc()
System.gc() 是“內存分配錯誤是運行 GC 的唯一原因”這一規則的一個例外。

雖然這可能是一種例外情況,但并不是一個好主意。請相信我。

文檔說明該調用設置了一個標志,該標志表明在 JVM 非常想要時可以運行 GC。System.gc() 調用實際上做的事情是:假如調用它的時候有一個 GC 循環正在運行,那么就?略這次調用;否則,就開始一次完整的 GC 循環。

這就是說,每次(或 99.9% 次)調用 System.gc() 的時候,您都會開始一個完整的 GC 循環。也許根本沒有必要運行 GC,但是您還是強行讓它執行完整個標記/掃描過程。您完全可以把 System.gc() 看作是 System.StopEverythingForAWhile() 調用或 System.SlugMyPerfomance() 調用。

對于這個調用,有一個可能的正當理由。因為假如沒有這個調用,直到堆用完 GC 才會運行。假如您有一個千兆字節的堆,在 GC 清理全部垃圾時,您將遭到相當大的打擊,然后您可能會考慮以固定間隔強行執行一個 GC 循環以達到“少量多次”的效果。但是,在這種情況下,您考慮調整堆的大小會更好些。

我們為什么要強行執行 GC?
到處散布 System.gc() 調用的誘惑非常大。在某一階段,我們總是碰到“內存溢出”的問題,第一反應是認為 GC 出了問題,并強行執行一個循環。盡管這經常能改善局面(至少是暫時能),并且似乎驗證了“GC 出了問題”這一想法,但事實也許并非如此。

請記住,GC 處于食物鏈的底部。由于 GC 的常規操作是徹底檢查系統運行時的狀態,所以代碼中其它地方所犯的錯誤經常會被 GC 暴露出來。這樣,別處所犯的錯誤導致 GC 沒有響應,而程序員認為 JVM 是在 GC 處異常結束的。因此,應該是 GC 的問題。追查要從定位問題開始,因此,我們強行讓 GC 在代碼中的不同地方執行。不幸的是,一旦了解了 GC 查出的問題的真相,我們總是會忘記刪除所有那些 System.gc() 調用。

在一天結束時,最終在您的代碼中會有成十、成百或者上千個強行執行 GC 的調用(您有多少個呢?)。除了緩慢的性能和在強制執行的非必要 GC 循環上花費過多的時間之外,這使您一無所獲。當答應 GC 按您預想的那樣運行時,您可能會感到吃驚,一個劣等系統的響應速度也如此之快。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 襄垣县| 邯郸市| 青州市| 大邑县| 谷城县| 闻喜县| 自贡市| 阿图什市| 南江县| 梨树县| 桐城市| 甘孜县| 城固县| 平利县| 郧西县| 阿坝县| 望奎县| 南澳县| 通化市| 天镇县| 玛纳斯县| 上林县| 喀喇沁旗| 深州市| 英德市| 阜新市| 张家界市| 龙胜| 墨玉县| 沈阳市| 岱山县| 新沂市| 南陵县| 安顺市| 东兰县| 政和县| 炉霍县| 兰州市| 玉田县| 福州市| 鄂州市|