Java 內存模型與內存結構


 Java內存模型


一、簡介

Java內存模型(JMM)主要是為了規定線程和內存之間的一些關系;根據JMM的設計,系統存在一個主內存(Main Memory)和工作內存(Work Memory),Java中所有變量都儲存在主內存中,對於所有線程都是共享的;每條線程都有自己的工作內存,工作內存中存儲了該線程已讀、寫共享變量的副本,工作內存是JMM的一個抽象概念,主要包括:緩存,寫緩沖區,寄存器以及其他的硬件和編譯器優化;線程對所有變量的操作都是在工作內存中進行的,線程之間無法相互直接訪問,變量傳遞均需要通過主內存完成。JMM示意圖如下:

二、JMM帶來了哪些問題?

1、可見性問題

CPU中運行的線程從主內存中拷貝共享對象obj到它的CPU緩存,把對象obj的count變量改為2,但這個變更對運行在右邊CPU中的線程不可見,因為這個更改還沒有flush到主內存中,要解決共享對象可見性這個問題,可以使用 volatile 或加鎖(如:synchronized),來保證可見性。

2、競爭問題

線程A和線程B共享一個對象obj,假設線程A從主存讀取Obj.count變量到自己的CPU緩存,同時,線程B也讀取了Obj.count變量到自己的CPU緩存,並且這兩個線程都對Obj.count做了加1操作;此時,Obj.count加1操作被執行了兩次,不過都在不同的CPU緩存中,如果這兩個加1操作是串行執行的,那么Obj.count變量便會在原始值上加2,最終主存中的Obj.count的值會是3;然而如果是並行操作,不管是線程A還是線程B先flush計算結果到主存,最終主內存中的Obj.count只會增加1次變成2;可以使用加鎖( 如:synchronized) 解決此問題,來保證一致性。

 3、重排序問題

在執行程序時,為了提高性能,編譯器和處理器常常會對指令做重排序。

可以使用volatile或加鎖(如:synchronized)來保證有序性。

Java內存結構


先看一下結構圖:

 

從圖中可以看出Java內存結構包括五大區域:堆、方法區、虛擬機棧、本地方法棧、程序計數器,其中堆、方法區線程共享,虛擬機棧、本地方法棧、程序計數器線程私有。

1、堆

堆是Java虛擬機管理的最大一塊內存區域,存放所有對象實例和數組,因為堆存放的對象是線程共享的,所以多線程的時候需要同步機制;堆又划分為:年輕代、老年代、永久代(JDK1.7)/元空間(JDK1.8),元空間與永久代的區別在於:永久代使用的是虛擬機內存,元空間則采用本地內存。

 

2、虛擬機棧

虛擬機棧描述的是線程進棧出棧的過程,線程結束內存自動釋放,它用來存儲當前線程運行方法所需要的數據、指令、返回地址(即局部變量和正在調用的方法),方法被調用時會在棧中開辟一塊叫棧幀的空間,方法運行在棧幀空間中。

3、本地方法棧

本地方法棧與虛擬機棧的作用十分相似,區別是虛擬機棧執行的是Java方法服務,而本地方法棧則為虛擬機使用native方法服務,可能底層調用的c或者c++方法。

4、方法區

方法區同堆一樣,是所有線程共享的內存區域,又被稱為非堆,用於存儲已被虛擬機加載的類信息、常量、靜態變量等。

5、程序計數器

程序計數器是一塊很小的內存空間,它是線程私有的,可以認作是當前線程的行號指示器。

 

參考:

[1] https://www.jianshu.com/p/8a58d8335270

[2] https://www.jianshu.com/p/de097e7a813a

[3] http://tutorials.jenkov.com/java-concurrency/java-memory-model.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM