判断Java 对象实例是否死亡
垃圾收集器與內存分配策略參考目錄:
1.判斷Java 對象實例是否死亡
2. Java 中的四種引用
3.垃圾收集算法
4. Java9中的GC 調優
5.內存分配與回收策略
在進入主題之前,我們要先知道運行時數據區域都是有哪些塊內存需要進行垃圾回收。
????程序計數器、虛擬機棧、本地方法棧、3個區域都是隨著線程生而生,隨著線程滅而滅的;棧中的棧幀隨著方法的進入和退出有條不紊的執行著進棧和出棧的操作。每一個棧幀中分配多大的內存基基本上在類結構確定下來后就已知了,因此這幾個區域的內存分配和回收都具備確定性,在這幾個區域就不需要過多的考慮垃圾回收的問題,因為 方法結束或者線程結束時,內存自然就跟著回收了。而Java 堆和方法區不一樣,一個接口中方的多個實現類需要的內存可能不一樣,一個方法的多個分支需要的內存可能有也不一樣,我們只有在程序處于運行期間才知道會創建哪些對象,這部分內存的分配和回收都是動態的,垃圾回收機制所關注的也是這部分內存。
在Java 堆里幾乎放著所有Java 對象的實例,垃圾收集器在對堆進行回收之前,第一件事就是要確定哪些對象是存活的,哪些對象已經”死去”。
????在進行GC Root 之前,我們先來了解一個判斷對象是否存活的算法:引用計數法。該算法的是這樣的:給對象中添加一個引用計數器,每當有一個地方引用它時,計數器值就加1 ;當引用失效時,計數器值就減1 ;任何時刻該計數器的值為0 時,就說明該對象是不可能再被使用的。
????引用計數算法(Reference Counting)的實現很簡單,效率也很高,在大部分情況下都是一個不錯的算法。但是目前Hot Spot 虛擬機并沒有使用這種算法來管理內存,因為這種算法很難解決對象之間相互引用的問題。下面就是一個簡單的例子,創建了兩個對象,這兩個對象都相互引用著對方,導致他們的引用計數器都不為0,所以引用計數法就不能通知GC 收集器收集他們,但這兩個對象除了相互引用之外沒有任何其他的用途。我打印了GC 日志以提供分析,為了防止大對象被直接分配到老年代,我把大對象分配到老年代的內存設置成了3m大小。
????由上面的圖(如果上圖看不清楚你可右鍵在新標簽頁面查看圖片)可以看出在進行垃圾回首之前新生代被占用了4744 K 大小,在GC 之后新生代的內存就被釋放了。因此這也可以說明虛擬機并不是通過引用計數法判斷對象是否能存活的。
可達性分析算法:
目前的主流程序語言的實現中,都是通過可達性分析(Reachability Analysis)來判定對象是否存活的。這個算法的基本思路就是一系列的稱為”GC Roots” 的對象作為起始點,從這些節點開始向下搜索,搜索所走過的路徑被稱為引用鏈(Reference Chain),當一個對象到GC Roots 沒有任何引用鏈相連時,則證明這個對象是不可用的(圖片來自百度搜索)。如圖所示,object5、object6、object7 雖然互有關聯,但是它們到GC Roots 是不可達的,所以它們將被判定為可回收的對象。
在Java 語言中可以作為GC Roots 的對象包括下面這幾種:
- 虛擬機棧中引用的對象
- 本地方法棧中引用的對象
- 堆中類靜態屬性引用的對象
????????????????????????????????????????????????????????????????????????????????????????????????????????????參考書籍:
????????????????????????????????????????????????????????????????????????????????????????????????????????????????《深入理解Java 虛擬機》周志明 著
總結
以上是生活随笔為你收集整理的判断Java 对象实例是否死亡的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 巴西的耕地比印度的耕地少的根本原因是什么
- 下一篇: 迷你世界黑科技软件电脑版下载(迷你世界黑