#1、硬件內存和JAVA內存html
#2、JAVA內存模型 按照官方的說法:Java 虛擬機具備一個堆,堆是運行時數據區域,全部類實例和數組的內存均今後處分配。
JVM主要管理兩種類型內存:堆和非堆,堆內存(Heap Memory)是在 Java 虛擬機啓動時建立,非堆內存(Non-heap Memory)是在JVM堆以外的內存。 簡單來講,堆是Java代碼可及的內存,留給開發人員使用的;非堆是JVM留給本身用的,包含方法區、JVM內部處理或優化所需的內存(如 JIT Compiler,Just-in-time Compiler,即時編譯後的代碼緩存)、每一個類結構(如運行時常數池、字段和方法數據)以及方法和構造方法的代碼。java
JVM 內存包含以下幾個部分:數組
堆內存(Heap Memory): 存放Java對象
非堆內存(Non-Heap Memory): 存放類加載信息和其它meta-data
其它(Other): 存放JVM 自身代碼等緩存
在JVM啓動時,就已經保留了固定的內存空間給Heap內存,這部份內存並不必定都會被JVM使用,可是能夠肯定的是這部分保留的內存不會被其餘進程使用,這部份內存大小由-Xmx 參數指定。而另外一部份內存在JVM啓動時就分配給JVM,做爲JVM的初始Heap內存使用,這部份內存是由 -Xms 參數指定。安全
#3、JAVA內存分配 Java的內存管理實際上就是變量和對象的管理,其中包括對象的分配和釋放。
多線程
JVM內存申請過程以下:併發
#4、JAVA內存間交互操做 關於主內存與工做內存之間的具體交互協議,即一個變量如何從主內存拷貝到工做內存、如何從工做內存同步到主內存之間的實現細節,Java內存模型定義瞭如下八種操做來完成:app
若是要把一個變量從主內存中複製到工做內存,就須要按順尋地執行read和load操做,若是把變量從工做內存中同步回主內存中,就要按順序地執行store和write操做。Java內存模型只要求上述操做必須按順序執行,而沒有保證必須是連續執行。也就是read和load之間,store和write之間是能夠插入其餘指令的,如對主內存中的變量a、b進行訪問時,可能的順序是read a,read b,load b, load a。Java內存模型還規定了在執行上述八種基本操做時,必須知足以下規則:優化
#5、原子性、可見性、有序性ui
除了volatile以外,Java還有兩個關鍵字能實現可見性,它們是synchronized。同步塊的可見性是由「對一個變量執行unlock操做以前,必須先把此變量同步回主內存中(執行store和write操做)」這條規則得到的,而final關鍵字的可見性是指:被final修飾的字段是構造器一旦初始化完成,而且構造器沒有把「this」引用傳遞出去,那麼在其它線程中就能看見final字段的值。 3. 有序性(Ordering)
Java內存模型中的程序自然有序性能夠總結爲一句話:若是在本線程內觀察,全部操做都是有序的;若是在一個線程中觀察另外一個線程,全部操做都是無序的。前半句是指「線程內表現爲串行語義」,後半句是指「指令重排序」現象和「工做內存主主內存同步延遲」現象。
Java語言提供了volatile和synchronized兩個關鍵字來保證線程之間操做的有序性,volatile關鍵字自己就包含了禁止指令重排序的語義,而synchronized則是由「一個變量在同一時刻只容許一條線程對其進行lock操做」這條規則來得到的,這個規則決定了持有同一個鎖的兩個同步塊只能串行地進入。
先行發生原則:
若是Java內存模型中全部的有序性都只靠volatile和synchronized來完成,那麼有一些操做將會變得很囉嗦,可是咱們在編寫Java併發代碼的時候並無感受到這一點,這是由於Java語言中有一個「先行發生」(Happen-Before)的原則。這個原則很是重要,它是判斷數據是否存在競爭,線程是否安全的主要依賴。
先行發生原則是指Java內存模型中定義的兩項操做之間的依序關係,若是說操做A先行發生於操做B,其實就是說發生操做B以前,操做A產生的影響能被操做B觀察到,「影響」包含了修改了內存中共享變量的值、發送了消息、調用了方法等。它意味着什麼呢?以下例:
//線程A中執行 i = 1;
//線程B中執行 j = i;
//線程C中執行 i = 2;
假設線程A中的操做」i=1「先行發生於線程B的操做」j=i「,那麼咱們就能夠肯定在線程B的操做執行後,變量j的值必定是等於1,結出這個結論的依據有兩個,一是根據先行發生原則,」i=1「的結果能夠被觀察到;二是線程C登場以前,線程A操做結束以後沒有其它線程會修改變量i的值。如今再來考慮線程C,咱們依然保持線程A和B之間的先行發生關係,而線程C出如今線程A和B操做之間,可是C與B沒有先行發生關係,那麼j的值多是1,也多是2,由於線程C對應變量i的影響可能會被線程B觀察到,也可能觀察不到,這時線程B就存在讀取到過時數據的風險,不具有多線程的安全性。
下面是Java內存模型下一些」自然的「先行發生關係,這些先行發生關係無須任何同步器協助就已經存在,能夠在編碼中直接使用。若是兩個操做之間的關係不在此列,而且沒法從下列規則推導出來的話,它們就沒有順序性保障,虛擬機能夠對它們進行隨意地重排序。
a.程序次序規則(Pragram Order Rule):在一個線程內,按照程序代碼順序,書寫在前面的操做先行發生於書寫在後面的操做。準確地說應該是控制流順序而不是程序代碼順序,由於要考慮分支、循環結構。
b.管程鎖定規則(Monitor Lock Rule):一個unlock操做先行發生於後面對同一個鎖的lock操做。這裏必須強調的是同一個鎖,而」後面「是指時間上的前後順序。
c.volatile變量規則(Volatile Variable Rule):對一個volatile變量的寫操做先行發生於後面對這個變量的讀取操做,這裏的」後面「一樣指時間上的前後順序。
d.線程啓動規則(Thread Start Rule):Thread對象的start()方法先行發生於此線程的每個動做。
e.線程終於規則(Thread Termination Rule):線程中的全部操做都先行發生於對此線程的終止檢測,咱們能夠經過Thread.join()方法結束,Thread.isAlive()的返回值等做段檢測到線程已經終止執行。
f.線程中斷規則(Thread Interruption Rule):對線程interrupt()方法的調用先行發生於被中斷線程的代碼檢測到中斷事件的發生,能夠經過Thread.interrupted()方法檢測是否有中斷髮生。
g.對象終結規則(Finalizer Rule):一個對象初始化完成(構造方法執行完成)先行發生於它的finalize()方法的開始。
h.傳遞性(Transitivity):若是操做A先行發生於操做B,操做B先行發生於操做C,那就能夠得出操做A先行發生於操做C的結論。
一個操做」時間上的先發生「不表明這個操做會是」先行發生「,那若是一個操做」先行發生「是否就能推導出這個操做一定是」時間上的先發生「呢?也是不成立的,一個典型的例子就是指令重排序。因此時間上的前後順序與先生髮生原則之間基本沒有什麼關係,因此衡量併發安全問題一切必須以先行發生原則爲準。
#6、JAVA內存管理 參考文獻:http://www.blogjava.net/chhbjh/archive/2012/01/28/368936.html
#7、JAVA安全沙箱 參考文獻:https://my.oschina.net/xionghui/blog/499725