談一談垃圾回收器

来源:http://www.cnblogs.com/mesopotamia/archive/2016/12/26/6224250.html
-Advertisement-
Play Games

目的: 使用垃圾回收器的唯一原因就是:回收程式不再使用的記憶體。 針對的目標對象: Java的垃圾回收器會自動回收不再使用的Java對象,釋放記憶體。但是回收的是用new創建的,分配在堆上的記憶體。 finalize(): 那麼,如果不是用這種方式創建的對象,該怎麼回收?比如:Java調用了本地的c語言方 ...


目的:

 

使用垃圾回收器的唯一原因就是:回收程式不再使用的記憶體。

 

針對的目標對象:

 

Java的垃圾回收器會自動回收不再使用的Java對象,釋放記憶體。但是回收的是用new創建的,分配在堆上的記憶體。

 

finalize():

 

那麼,如果不是用這種方式創建的對象,該怎麼回收?比如:Java調用了本地的c語言方法創建了個對象,那麼這時,該對象不是放在堆上的。除非你手動去調用c的free()方法,否則,這個對象將永遠不會被清理。

 

Java的finalize()方法可以解決上面的問題。垃圾回收器在回收垃圾對象時,會首先去調用該對象的finalize()方法。所以,你可以在finalize()方法中調用c的free()方法。

 

一般教科書會寫,finalize()用於垃圾回收之前的清理工作,而實際上,除了上面講的極少數情況之外,我們一般情況下並不需要使用finalize()。

 

不保證發生:

 

雖然Java的垃圾回收器會根據對象的使用情況自動清理記憶體,但並不一定會發生,如果記憶體還夠用的話,虛擬機一般是不會浪費時間去作清理工作的。

 

如何判斷Java對象可以回收:

 

1.不被使用的“引用計數器法”:

 

每個對象都含有一個引用計數器,當有引用變數指向該對象時,引用計數器+1,當這個引用變數不再指向該對象,或者被置為null時,計數器-1。如下圖:

 

 

當第四種情況發生時,即:沒有引用變數指向“李四”那個對象了,這時,垃圾回收器在恰當的時候就會把李四所在的對象回收掉。

 

它簡單便捷,但是之所以沒被Java虛擬機採用的原因是:無法解決迴圈引用的問題。舉個簡單的例子:

 

 

objA有個instance變數,objB也有個instance變數,讓objA的instance指向B對象,而讓objB的instance變數指向A對象,那麼,B對象和A對象的引用計數器都是1,不為0,如果按照引用計數器的方法,A和B就不能被回收,但事實是,objA和objB這兩個引用變數已經是null了(它們指向的具體對象已經不再被引用了)。

 

2.根搜索演算法

 

在主流的商用程式語言中(Java和C#,甚至古老的人Lisp語言),都是使用根搜索演算法(GC Roots Tracing)判定對象是否存活的。

 

之前講過,對象的引用是放在棧中的,常量的引用是放在常量池之中的。如圖:

 

 

根搜索演算法的思想是,從常量池和棧中的引用變數開始遍歷所有的引用變數,找到所有的活的對象(引用不為null)。然後再繼續尋找這個對象所包含的所有引用,反覆進行,直到所有引用網路被訪問完為止。

 

常量池或棧中的引用變數是根節點,擴展出的整個網路就是一個引用鏈。最後,如果最終發現有對象到根節點的路徑是不可達的,說明這個對象是可回收的,這就解決了迴圈引用的問題:

 



如上圖,GCRoots是根節點,object5、6、7雖然各自引用,但是它們到GCRoots都是不可達的,所以,它們是可以被回收的。

 

怎樣回收?

 

每個虛擬機採用的回收演算法是不同的,經典的案例如下:

 

標記-清除演算法:

 

在使用“根搜索演算法”尋找引用變數的同時,虛擬機會給每個存活的對象做一個標記,全部標記完成的時候才進行清除工作。

 

這樣的問題是,存活的對象在堆中不是連續存儲的,那麼清除“死亡”對象後,記憶體中就會留下大量碎片,如果在後面需要用到大記憶體對象時,記憶體空間不夠,就要重新整理記憶體。如圖回收前:

 


 

回收後:

 

 

複製演算法:

 

它將可用記憶體按容量劃分為大小相等的兩塊,每次只使用其中的一塊。當這一塊的記憶體用完了,就將還存活著的對象複製到另外一塊上面,然後再把已使用過的記憶體空間一次清理掉。如圖回收前:

 

 

回收後(把存活著的對象搬到右側,左側剩下的就都是可清理的,然後統統清理掉。當右側需要清理的時候,類似的,把存活的對象再搬到左側,然後清空右側):

 

 

這種方式的缺點:很顯然,可用記憶體只有原來的一半兒。還有個缺點:如果左側大量的都是存活的對象,清理時仍然要全部搬到右側,很浪費時間。

 

現在的商業虛擬機都採用這種收集演算法,但是保留區與運作區的比例有不同,且詳細又將堆記憶體劃分為新生代、老年代。新生代 ( Young ) 又被劃分為三個區域:Eden、From Survivor、To Survivor。關於新生代、老年代、堆記憶體等,詳細可查閱關於Java虛擬機的資料瞭解。

 

 

 


參考資料:

1.Thinking in Java 第5.5.4章節。

2.cnblogs:Java垃圾收集器:

http://www.cnblogs.com/gw811/archive/2012/10/19/2730258.html

3.blogjava:Java堆記憶體:

http://www.blogjava.net/fancydeepin/archive/2013/09/29/jvm_heep.html

 

更多內容請關註微信訂閱號:it_pupil


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 做web開發一直用到分頁控制項,自己也動手實現了個,使用用戶自定義控制項。 翻頁後數據載入使用委托,將具體實現放在在使用分頁控制項的頁面進行註冊。 有圖有真相,給個直觀的認識: 自定義分頁控制項前臺代碼: 自定義分頁控制項後臺代碼: 當前頁碼、總共多少條記錄使用ViewState記錄狀態信息,因為導航控制項會引 ...
  • 堅持每天寫一個總結的博客,今天又是一個新的開始! 今天我要說的是一個關於發送簡訊通知發送的問題。具體的業務流程是這樣的,現在需要對用戶的一個提現的申請進行審核,審核的內部需要控制很多的業務, 1.檢查用戶的提現餘額-> 2.減去用戶的賬戶金額->3.減去公司的結算賬戶的餘額-> 4.創建用戶的提現日 ...
  • 可能很多人看到這個標題會有疑問:什麼是土巴啊里模式?一開始我也納悶:難道是土巴兔和阿裡巴巴的結合產物?先不急,聽我慢慢說來。 先提阿裡巴巴,阿裡巴巴是中國第一個做網上批發市場的網站,通過互聯網進行信息傳遞,不受時間和空間的限制。你可以在瞬間將某種商品的圖案、動畫、規格、價格、交貨方式等信息傳到萬里之 ...
  • Python預設版本修改 當電腦安裝了多個版本的Python,而Shell中預設的Python不是你想要的,這個時候就需要對Python的預設版本進行修改。 在Windows中,可以通過修改環境變數的方式來達到目的。 具體做法是在系統屬性的高級選項卡中選擇環境變數: 接著在系統變數中選擇Path進行 ...
  • 今日問題: 請問主程式輸出結果是什麼?(點擊以下“【Java每日一題】20161227”查看20161226問題解析) 題目原發佈於公眾號、簡書:【Java每日一題】20161227,【Java每日一題】20161227 註:weknow團隊近期開通並認證了分答,歡迎大家收聽,有問題也歡迎到分答來咨 ...
  • 第1個導航 1 2 3 4 第2個導航 1 2 3 第3個導航 1 2 第4個導航 ... ...
  • 一、包的概念:創建,使用。 1.新建包: 最上面一行,之前不能再有其它代碼了。 package 包名; 註意:包名一般都有命名的規範。例如:com.itnba.maya.zy(從大到小)。 2.使用包: import 包名.*; import 包名.類名; 例如:import com.itnba.m ...
  • 這個類在日常的開發中,還是非常常用的。今天就總結一下Arrays工具類的常用方法。最常用的就是asList,sort,toStream,equals,copyOf了。另外可以深入學習下Arrays的排序演算法,這個還是非常有用的。 所有的方法都是在下麵的類中進行測試的: asList 這個方法可以把數 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...