文章目錄整體架構(gòu)JVM = 類加載器(classloader) 執(zhí)行引擎
(executionengine) 運行時數(shù)據(jù)區(qū)域(runtime dataarea)
java每個線程都有一個虛擬機棧
類加載器 ClassLoader1.加載過程 7 個步驟 加載–>驗證–>準備–>解析–>初始化–>使用–>卸載
 2.ClassLoader–>BaseDexClassLoader–>PathClassLoder ,DexClassLoader 3.雙親委托模式 先走父類的加載器加載類,若果沒有找打父類才會輪到自己,好處 避免重復(fù)加載 安全 運行時數(shù)據(jù)區(qū)1.程序計數(shù)器 : 我們知道對于一個處理器(如果是多核cpu那就是一核),在一個
確定的時刻都只會執(zhí)行一條線程中的指令,一條線程中有多個指
令,為了線程切換可以恢復(fù)到正確執(zhí)行位置,每個線程都需有獨
立的一個程序計數(shù)器,不同線程之間的程序計數(shù)器互不影響,獨立存儲。
2.本地方法棧 : 簡單的理解為 C 代碼的執(zhí)行去 3.堆 : 簡單的說就是對象的存儲區(qū),它是被所有線程共享的一塊區(qū)域 堆是java虛擬機管理內(nèi)存最大的一塊內(nèi)存區(qū)域,因為堆存放的
對象是線程共享的,所以多線程的時候也需要同步機制。
堆 回收算法使用的復(fù)制算法 效率高 沒有碎片 利用率低
分為三個區(qū) eden from to (survivor) 按照 8:1:1因為大多數(shù)的對象都是朝生夕死的。
4.棧 : 棧描述的是Java方法執(zhí)行的內(nèi)存模型。
每個方法被執(zhí)行的時候都會創(chuàng)建一個棧幀用于存儲局部變量表,
操作棧,動態(tài)鏈接,方法出口等信息。每一個方法被調(diào)用的過程
就對應(yīng)一個棧幀在虛擬機棧中從入棧到出棧的過程。
5.方法區(qū) 方法區(qū)同堆一樣,是所有線程共享的內(nèi)存區(qū)域,為了區(qū)分堆,又
被稱為非堆。用于存儲已被虛擬機加載的類信息、常量、靜態(tài)變
量,如static修飾的變量加載類的時候就被加載到方法區(qū)中。
6.GC 堆的回收為了高效的回收,jvm將堆分為三個區(qū)域 1.新生代(Young Generation)NewSize和MaxNewSize分別可以控制年輕代的初始大小和最大的大小 2.老年代(Old Generation) 3.永久代(Permanent Generation)【1.8以后采用元空間,就不在堆中了】 對象是否存活 引用計數(shù)算法 早期判斷對象是否存活大多都是以這種算法,這種算法判斷很簡單,簡單來說就是給對象添加一個引用計數(shù)器,每當(dāng)對象被引用一次就加1,引用失效時就減1。當(dāng)為0的時候就判斷對象不會再被引用。 優(yōu)點:實現(xiàn)簡單效率高,被廣泛使用與如python何游戲腳本語言上。 缺點:難以解決循環(huán)引用的問題,就是假如兩個對象互相引用已經(jīng)不會再被其它其它引用,導(dǎo)致一直不會為0就無法進行回收。 可達性分析算法 目前主流的商用語言[如java、c#]采用的是可達性分析算法判斷對象是否存活。這個算法有效解決了循環(huán)利用的弊端。 它的基本思路是通過一個稱為“GC Roots”的對象為起始點,搜 索所經(jīng)過的路徑稱為引用鏈,當(dāng)一個對象到GC Roots沒有任何引用跟它連接則證明對象是不可用的。
回收算法
1.標(biāo)記/清除算法【最基礎(chǔ)】 (老年代 標(biāo)記清楚 、整理 新生代 是復(fù)制算法) 標(biāo)記 也是紅灰白 對灰色進行清除 標(biāo)記整理是紅色進行整
理 ,清楚會有很多碎片,效率高
2.復(fù)制算法 復(fù)制內(nèi)存區(qū)域,標(biāo)記 紅藍灰白色 紅色不可回收 灰色可回
收 白色沒有分配 藍色 預(yù)留 , 效率高,內(nèi)存復(fù)制沒有碎
片,缺點 利用率只有一半()
3.標(biāo)記/整理算法 jvm采用`分代收集算法`對不同區(qū)域采用不同的回收算法。
其中新生代使用的是復(fù)制算法,老年代使用的是標(biāo)記清除、標(biāo)記整理算法?!?/code>
jvm 三大特性 可見性 原子性 有序性volatile 具有可見性和禁止命令重排序,不保證原子性。所以能夠達到一次修改其他線程可見 原子性即一個操作或者多個操作 要么全部執(zhí)行并且執(zhí)行的過程不會被任何因素打斷,要么就都不執(zhí)行。
例如 i=0 只有一步操作 把0賦給變量i i 則不是,先取出i 再執(zhí)行i 1 最后把結(jié)果賦給i 進行了三部,不符合原子性 在單線程環(huán)境下我們可以認為以上都是原子性操作,但是在多線程環(huán)境下則不同,Java只保證了基本數(shù)據(jù)類型的變量和賦值操作才是原子性的(注:在32位的JDK環(huán)境下,對64位數(shù)據(jù)的讀取不是原子性操作*,如long、double)。要想在多線程環(huán)境下保證原子性,則可以通過鎖、synchronized來確保。
可見性可見性是指當(dāng)多個線程訪問同一個變量時,一個線程修改了這個變量的值,其他線程能夠立即看得到修改的值。
有序性有序性:即程序執(zhí)行的順序按照代碼的先后順序執(zhí)行。
volatile實現(xiàn)原理volatile可以保證線程可見性且提供了一定的有序性,但是無法保證原子性,即 volatile 保證了 可見性和有序性 沒有原子性 。在JVM底層volatile是采用“內(nèi)存屏障”來實現(xiàn)的。
有了CPU高速緩存雖然解決了效率問題,但是它會帶來一個新的問題:數(shù)據(jù)一致性。在程序運行中,會將運行所需要的數(shù)據(jù)復(fù)制一份到CPU高速緩存中,在進行運算時CPU不再也主存打交道,而是直接從高速緩存中讀寫數(shù)據(jù),只有當(dāng)運行結(jié)束后才會將數(shù)據(jù)刷新到主存中。舉一個簡單的例子: i i
當(dāng)線程運行這段代碼時,
首先會從主存中讀取i( i = 1),
然后復(fù)制一份到CPU高速緩存中,
然后CPU執(zhí)行 1 (2)的操作,
然后將數(shù)據(jù)(2)寫入到告訴緩存中,
最后刷新到主存中。
其實這樣做在單線程中是沒有問題的,有問題的是在多線程中。如下:
假如有兩個線程A、B都執(zhí)行這個操作(i ),按照我們正常的邏輯思維主存中的i值應(yīng)該=3,但事實是這樣么?分析如下:
兩個線程從主存中讀取i的值(1)到各自的高速緩存中,然后線程A執(zhí)行 1操作并將結(jié)果寫入高速緩存中,最后寫入主存中,此時主存i==2,線程B做同樣的操作,主存中的i仍然=2。所以最終結(jié)果為2并不是3。這種現(xiàn)象就是緩存一致性問題。
通過在總線加LOCK#鎖的方式 通過緩存一致性協(xié)議 但是方案1存在一個問題,它是采用一種獨占的方式來實現(xiàn)的,即總線加LOCK#鎖的話,只能有一個CPU能夠運行,其他CPU都得阻塞,效率較為低下。 第二種方案,緩存一致性協(xié)議(MESI協(xié)議)它確保每個緩存中使用的共享變量的副本是一致的。其核心思想如下:當(dāng)某個CPU在寫數(shù)據(jù)時,如果發(fā)現(xiàn)操作的變量是共享變量,則會通知其他CPU告知該變量的緩存行是無效的,因此其他CPU在讀取該變量時,發(fā)現(xiàn)其無效會重新從主存中加載數(shù)據(jù)。
一個int變量,用volatile修飾,多線程去操作 ,線程安全嗎? 不安全。volatile只能保證可見性,并不能保證原子性。
i 實際上會被分成多步完成:
1)獲取i的值;
2)執(zhí)行i 1;
3)將結(jié)果賦值給i。
volatile只能保證這3步不被重排序,多線程情況下,可能兩個線程同時獲取i,執(zhí)行i 1,然后都賦值結(jié)果2,實際上應(yīng)該進行兩次 1操作。
那如何才能保證i 線程安全? 可以使用java.util.concurrent.atomic包下的原子類,如AtomicInteger。 其實現(xiàn)原理是采用CAS自旋操作更新值。CAS即compare and swap的縮寫,中文翻譯成比較并交換。CAS有3個操作數(shù),內(nèi)存值V,舊的預(yù)期值A(chǔ),要修改的新值B。當(dāng)且僅當(dāng)預(yù)期值A(chǔ)和內(nèi)存值V相同時,將內(nèi)存值V修改為B,否則什么都不做。自旋就是不斷嘗試CAS操作直到成功為止。 CAS實現(xiàn)原子操作會出現(xiàn)什么問題? ABA問題。因為CAS需要在操作之的時候,檢查值有沒有發(fā)生變化,如果沒有發(fā)生變化則更新,但是如果一個值原來是A,變成,有變成A,那么使用CAS進行檢查時會發(fā)現(xiàn)它的值沒有發(fā)生變化,但實際上發(fā)生了變化。ABA問題可以通過添加版本號來解決。Java 1.5開始,JDK的Atomic包里提供了一個類AtomicStampedReference來解決ABA問題。 循環(huán)時間長開銷大。pause指令優(yōu)化。 只能保證一個共享變量的原子操作??梢院喜⒊梢粋€對象進行CAS操作。 參考 https://www.jianshu.com/p/76959115d486 //這個文章比較好,講解了volatile 同時還講解了jvm內(nèi)存模型 https://www.cnblogs.com/chenssy/p/6379280.html
|