java虛擬機和內存模型

1.垃圾收集器概述

垃圾收集器(Garbage Collection),通常被稱作GC。
GC主要做了兩個工作,一個是內存的劃分和分配,一個是對垃圾進行回收。
關於對垃圾進行回收,被引用的對象是存活的對象,而不被引用的對象是死亡的對象也就是垃圾,GC要區分出存活的對象和死亡的對象,也就是垃圾標記,並對垃圾進行回收。

2.垃圾標記算法

在對垃圾進行回收前,GC要先標記出垃圾,那麼如何標記呢,目前有兩種垃圾標記算法,分別是 引用計數算法根搜索算法
(1)引用計數算法的基本思想就是每個對象都有一個引用計數器,當對象在某處被引用的時候,它的引用計數器就加1,引用失效時就減1。當引用計數器中的值變爲0,則該對象就不能被使用成了垃圾。目前主流的Java虛擬機沒有選擇引用計數算法來爲垃圾標記,主要原因是引用計數算法沒有解決對象之間相互循環引用的問題。
(2)根搜索算法的基本思想就是選定一些對象作爲GC Roots,並組成根對象集合,然後從這些作爲GC Roots的對象作爲起始點,向下進行搜索,如果目標對象到GC Roots是連接着的,我們則稱該目標對象是可達的,如果目標對象不可達則說明目標對象是可以被回收的對象

被標記爲不可達的對象會立即被垃圾收集器回收嗎?很顯然是不會的,被標記爲不可達的對象會進入收集階段,這時會執行該對象重寫的finalize方法,如果沒有重寫finalize方法或者finalize方法中沒有重新與一個可達的對象進行關聯纔會進入終結階段,並最終被回收。

垃圾被標記後,GC就會對垃圾進行收集,垃圾收集有很多種算法
(1)標記-清除算法
缺點:(1)標記和清除的效率都不高(2)容易產生大量不連續的內存碎片,碎片太多可能會導致後續沒有足夠的連續內存分配給較大的對象,從而提前觸發新的一次垃圾收集動作
(2)複製算法
它把內存空間劃爲兩個相等的區域,每次只使用其中一個區域。垃圾收集時,遍歷當前使用的區域,把存活對象複製到另外一個區域中,最後將當前使用的區域的可回收的對象進行回收。
這種算法每次都對整個半區進行內存回收,不需要考慮內存碎片的問題,代價就是使用內存爲原來的一半。
複製算法的效率跟存活對象的數目多少有很大的關係,如果存活對象很少,複製算法的效率就會很高。由於絕大多數對象的生命週期很短,並且這些生命週期很短的對象都存於新生代中,所以複製算法被廣泛應用於新生代中
(3)標記-壓縮算法
在新生代中可以使用複製算法,但是在老年代就不能選擇複製算法了,因爲老年代的對象存活率會較高,這樣會有較多的複製操作,導致效率變低。標記-清除算法可以應用在老年代中,但是它效率不高,在內存回收後容易產生大量內存碎片。因此就出現了一種標記-壓縮算法(Mark-Compact)算法,與標記-清除算法不同的是,在標記可回收的對象後將所有存活的對象壓縮到內存的一端,使他們緊湊的排列在一起,然後對端邊界以外的內存進行回收。回收後,已用和未用的內存都各自一邊

http://liuwangshu.cn/tags/Java%E8%99%9A%E6%8B%9F%E6%9C%BA/

3.內存模型

線程之間的通信機制有兩種:共享內存和消息傳遞
在共享內存的併發模型裏,線程之間共享程序的公共狀態,線程之間通過寫-讀內存中的公共狀態來隱式進行通信
在消息傳遞的併發模型裏,線程之間沒有公共狀態,線程之間必須通過明確的發送消息來顯式進行通信。
Java的併發採用的是共享內存模型,Java線程之間的通信總是隱式進行,整個通信過程對工程師完全透明。
線程A與線程B之間如要通信的話(共享內存模型),必須要經歷下面2個步驟:
1.線程A把本地內存A中更新過的共享變量刷新到主內存中去。
2.線程B到主內存中去讀取線程A之前已更新過的共享變量。
(所以中斷線程的標記位必須要聲明爲volatile,讓修改過的變量立馬刷新到主存中去)

http://liuwangshu.cn/java/concurrent/4-jmm.html
http://blog.csdn.net/column/details/14531.html?&page=1

博主的一系列文章都不錯,所有的地址在這裏:http://liuwangshu.cn/system/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章