在java中應爲不一樣的目的能夠將java劃分爲兩種內存模型:gc內存模型。併發內存模型。java
java與c++之間有一堵由內存動態分配與垃圾收集技術所圍成的「高牆」。牆外面的人想進去,牆裏面的人想出來。c++
java在執行java程序的過程當中會把它管理的內存劃分若干個不一樣功能的數據管理區域。如圖:數組
總體上。分爲三部分:棧,堆,程序計數器,他們每一部分有其各自的用途;虛擬機棧保存着每一條線程的執行程序調用堆棧;堆保存着類對象、數組的具體信息;程序計數器保存着每一條線程下一次執行指令位置。這三塊區域中棧和程序計數器是線程私有的。也就是說每個線程擁有其獨立的棧和程序計數器。咱們能夠看看具體結構:緩存
在棧中,會爲每個線程建立一個棧。線程越多,棧的內存使用越大。對於每個線程棧。當一個方法在線程中執行的時候,會在線程棧中建立一個棧幀(stack frame),用於存放該方法的上下文(局部變量表、操做數棧、方法返回地址等等)。每個方法從調用到執行完畢的過程,就是對應着一個棧幀入棧出棧的過程。併發
本地方法棧與虛擬機棧發揮的做用是相似的,他們之間的區別不過是虛擬機棧爲虛擬機執行java(字節碼)服務的,而本地方法棧是爲虛擬機執行native方法服務的。優化
在hotspot的實現中,方法區就是在堆中稱爲永久代的堆區域。幾乎全部的對象/數組的內存空間都在堆上(有少部分在棧上)。在gc管理中,將虛擬機堆分爲永久代、老年代、新生代。經過名字咱們能夠知道一個對象新建通常在新生代。通過幾輪的gc。還存活的對象會被移到老年代。永久代用來保存類信息、代碼段等幾乎不會變的數據。堆中的全部數據是線程共享的。spa
新生代:應爲gc具體實現的優化的緣由。hotspot又將新生代劃分爲一個eden區和兩個survivor區。每一次新生代gc時候。只用到一個eden區,一個survivor區。新生代通常的gc策略爲mark-copy。操作系統
老年代:當新生代中的對象通過若干輪gc後還存活/或survisor在gc內存不夠的時候。會把當前對象移動到老年代。老年代通常gc策略爲mark-compact。線程
永久代:永久代通常能夠不參與gc。應爲其中保存的是一些代碼/常量數據/類信息。在永久代gc。清楚的是類信息以及常量池。對象
如同其名稱同樣。程序計數器用於記錄某個線程下次執行指令位置。程序計數器也是線程私有的。
java試圖定義一個Java內存模型(java memory model jmm)來屏蔽掉各類硬件/操做系統的內存訪問差別,以實現讓java程序在各個平臺下都能達到一致的內存訪問效果。java內存模型主要目標是定義程序中各個變量的訪問規則,即在虛擬機中將變量存儲到內存和從內存中取出變量這樣的底層細節。模型圖以下:
java內存模型中規定了全部變量都存貯到主內存(如虛擬機物理內存中的一部分)中。每個線程都有一個本身的工做內存(如cpu中的高速緩存)。線程中的工做內存保存了該線程使用到的變量的主內存的副本拷貝。線程對變量的全部操做(讀取、賦值等)必須在該線程的工做內存中進行。不一樣線程之間沒法直接訪問對方工做內存中變量。線程間變量的值傳遞均須要經過主內存來完成。
關於主內存與工做內存之間的交互協議,即一個變量如何從主內存拷貝到工做內存。如何從工做內存同步到主內存中的實現細節。java內存模型定義了8種操做來完成。這8種操做每一種都是原子操做。8種操做以下:
lock(鎖定):做用於主內存,它把一個變量標記爲一條線程獨佔狀態;
unlock(解鎖):做用於主內存,它將一個處於鎖定狀態的變量釋放出來,釋放後的變量纔可以被其餘線程鎖定;
read(讀取):做用於主內存,它把變量值從主內存傳送到線程的工做內存中,以便隨後的load動做使用;
load(載入):做用於工做內存,它把read操做的值放入工做內存中的變量副本中;
use(使用):做用於工做內存,它把工做內存中的值傳遞給執行引擎,每當虛擬機遇到一個須要使用這個變量的指令時候,將會執行這個動做;
assign(賦值):做用於工做內存,它把從執行引擎獲取的值賦值給工做內存中的變量,每當虛擬機遇到一個給變量賦值的指令時候,執行該操做;
store(存儲):做用於工做內存,它把工做內存中的一個變量傳送給主內存中,以備隨後的write操做使用;
write(寫入):做用於主內存,它把store傳送值放到主內存中的變量中。