Java內存模型中,程序(進程)擁有一塊內存空間,能夠被全部的線程共享,即MainMemory(主內存);而每一個線程又有一塊獨立的內存空間,即WorkingMemory(工做內存)。普通狀況下,當線程須要對某一共享變量進行修改時,一般會進行以下的過程:html
1. 從主內存中拷貝變量的一份副本,並裝載到工做內存中;算法
2. 在工做內存中執行代碼,修改副本的值;安全
3. 用工做內存中的副本值更新主存中的相關變量值。多線程
以下圖:併發
所謂「線程安全」,即多個線程同時執行同一段代碼時,不會出現不肯定的或者與單線程條件下不一致的結果。一般,下列三種條件居其一的併發訪問被JVM認爲是線程安全的:.net
1. 有final關鍵字修飾且已被賦值;線程
2. 有volatile關鍵字修飾;htm
3. 有鎖保護(synchronized、ReentrantLock等)。對象
第1點顯而易見,再也不贅述。blog
volatile關鍵字的做用是告知JVM:它所修飾的域的原子操做都不須要通過線程的工做內存,而直接在主內存中進行修改。這樣就保證了線程從主內存中讀取(read)它的值的時候,老是最新的。可是,Java中的運算極少是原子的,即使是像++ 這樣的一元運算符或者+= 這樣的二元運算符都不是原子的,所以volatile關鍵字修飾的域在多線程環境下依然可能會讀寫出「髒」數據:它只保證每一步原子操做的線程安全,但不保證整個操做過程的線程安全。也所以,volatile主要被用於變量只有原子操做的場合,如賦值、移位等。
鎖,不管是顯式(ReentrantLock)仍是隱式(synchronized)的同步鎖,或是信號量(Semaphore),抑或是阻塞隊列(BlockingQueue),仍是其它的同步措施(CyclicBarrier、CountDownLatch、wait¬ify等),它們的做用都是同樣的,就是保證一個共享變量的副本進入到某個線程的工做內存以後,該共享變量就再也不會被其它線程訪問到,直到前述過程的第3步執行完成。
線程在有同步鎖的狀況下訪問共享變量的過程以下:
1. 獲取同步鎖
2. 清空工做內存
3. 從主內存將拷貝變量副本,並裝載到工做內存
4. 對副本執行代碼
5. 用副本數據更新主內存中的相關變量
6. 釋放同步鎖
一般,沒有得到同步鎖的線程將被阻塞,直到它競爭到同步鎖。這樣,沒有得到同步鎖的線程不只不能訪問數據,甚至都不能繼續運行,因而強迫性地保證了線程安全。也所以,線程安全代碼的開銷要大於不安全的代碼,同步鎖的開銷也要大於volatile。
上述線程運行的過程其實是JVM的思惟模型。JVM真正的邏輯內存模型以下圖所示:
其中:
線程的工做內存位於JVM棧中。線程中的每一個方法在運行的時候都會在棧中申請一個幀(frame),用來保存變量表、操做集、動態連接、出入口等信息。每一個方法從調用到返回,就是它的幀在線程棧中從入棧到出棧的過程。
程序的主內存位於JVM堆。程序中的每個實例或數據域都會被分配到堆中,並由全部線程共享(若是有權限的話)。線程從主內存中拷貝變量副本的過程,就是從堆中讀取(read)該變量的數據,而後在本身的棧中建立(load)一個新的實例。可見,load以後,棧中的操做就與堆中的變量沒有關係了。
線程PC用於寄存每一個線程當前執行到的機器指令。本地方法棧用於調用JNI方法,並在方法調用結束後銷燬。
Java的垃圾收集就是針對堆中的對象進行的。堆中按照對象的生命週期長短分爲以下圖的幾個區域:
其中:
新生代(NewGeneration)分爲兩個區:Eden和Survivor;而Survivor區又分爲了等大的兩個區:S0和S1(或From和To)。新建立(new)的對象都會分配到Eden區中。當Eden區滿時,會觸發一次MinorGC,JVM會將Eden中存活的對象進行標記並拷貝到S0中,同時回收全部無效的對象。當S0滿時,S0中存活的對象被拷貝到S1區,無效的對象被回收。當S1也滿時,意味着整個新生代都滿了,此時將觸發一次MajorGC,新生代中部分存活的對象被標記後拷貝到老年代區中,無效的對象被回收,同時新生代中剩餘的對象按必定的規則分配到Eden、S0、S1中。
老年代(OldGeneration)中保存的,是屢次GC以後仍然存活的對象。在老年代區中,若是剩餘的任一連續內存空間都不足以容納一個對象時,須要對老年代區進行碎片壓縮,此時程序將掛起。當老年代滿時,將觸發一次FullGC,它先對新生代發起一次MinorGC,再在老年代區標記清除無效的對象。
持久代(PermanentGeneration)也就是前圖中堆內部的方法區。這裏存放了程序中每一個Class和ClassLoader以及一些常量的數據信息。其中又包含了常量池,用於保存常量數據、方法簽名等在編譯時就決定的不變量。持久代中一般極少、甚至不發生GC。
GC中的算法參見以下的連接:
http://www.cnblogs.com/aigongsi/archive/2012/04/06/2434771.html
http://www.cnblogs.com/aigongsi/archive/2012/04/13/2446166.html
轉自:
http://blog.csdn.net/sadfishsc/article/details/10325879