JVM內存結構—JAVA內存模型—JAVA對象模型

上一篇文章寫了JAVA的垃圾回收機制,提到垃圾回收機制主要是發生在堆內存中(極少可能發生在方法區中),這裏便有同學會聯想到我堆棧方法區都沒搞清楚,你直接來堆內存的垃圾回收機制了,那這篇文章就直接來講講JVM內存結構以及它另外兩個傻傻分不清名字的兄弟:JAVA內存模型與JAVA對象模型。
記錄目前主要爲自己加深理解,後期會加入自己畫的配圖供大家理解。

JAVA內存結構

首先,五大重要組成部分。

所有線程共享
主要存放各種對象和數組

方法區

所有線程共享
主要存放類的定義、常量、靜態變量
相當於永久代

java虛擬機棧

線程獨享
存放java方法的棧針
基本數據類型和對象引用
參與方法的調用與返回

本地方法棧

線程獨享
存放native方法的棧針

程序計數器

線程獨享
記錄指令的位置

其實還有一個直接內存的部分,它不屬於運行時數據區,也不是java虛擬機規範中定義的內存區域。

java內存模型(JAVA MEMORY MODEL)

衆所周知java是一門跨平臺的語言,不同系統上的虛擬機對於java語言中一些處理理解不一樣,導致最終的運行結果不一樣,於是就有JMM的這種規範。
JMM規定程序所有的變量都存儲在主內存中,每個線程都擁有一份主內存的副本,線程對變量的操作必須在工作內存中進行,線程與線程之間不能直接進行數據交互,而只能通過工作內存和主內存之間的數據同步,JMM主要是規定數據同步的方式和時間。
JMM包括三種特性:

排序性

不同的系統對程序指令順序會有自己獨特的優化,在其帶來程序速度的同時也會因爲重排序產生一系列不可預知的問題,而JMM中volatile關鍵字所修飾的屬性會禁止指令重排,synchronized關鍵字會將程序轉化爲單線程形式,從而避免重排序帶來的影響。其中volatile關鍵字使用了內存屏障,即Load屏障和Store屏障,其規定:
在寫之前加StoreStore屏障,在寫之後加StoreLoad屏障
在讀之前加LoadLoad屏障,在讀之後加LoadStore屏障

可見性

因爲線程對變量的操作完全在從主內存拷貝過來的副本上的,這樣就有可能導致不同線程對同一個變量的修改無法統一,volatile關鍵字所修飾的屬性一旦被修改則馬上同步到內存,一旦要讀取則必須從主存中讀取。

happens-before規則很好地保證了可見性

  1. 單線程規則
  2. 鎖操作(synchronized和lock)
  3. volatile修飾
  4. 線程啓動 start()方法
  5. 傳遞性
  6. finalize()一定是最後執行的
  7. 線程join方法
  8. 中斷:一個線程被interrupt時,檢測中斷isInterrupted一定能檢測到。

原子性

JMM要求操作必須是原子性的,這樣也能避免線程在一些關鍵的操作上互相穿插而導致的錯誤結果,synchronized關鍵字則將其保護的操作限定爲一種單線程的操作,主要是得益於monitorenter(從主存中刷新變量值到工作內存中)和monitorexit(將最新值從工作內存中刷新到主存中)兩個高級指令。
在講到內存同步問題的時候不得不提的就是兩個方法:
CountDownLatch:計數器遞減使得某線程在等待其他線程執行完成後執行,不可複用
CyclIcBarrier:計數器遞增使得線程之間相互等待直至達到閾值後繼續執行,可複用

Java對象模型

即java對象的存儲結構:主要分爲三個區域
棧:保存對象的引用和基本數據類型
堆:保存對象的實例(對象頭(markworld代表hashcode、鎖狀態、gc年齡等,元數據表示目標類的類型信息)、實例數據。對齊填充)
方法區:類的模型 instanceKlass(被元數據指向)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章