1. 程式人生 > >了解java內存模型,看這裏就夠了

了解java內存模型,看這裏就夠了

空間大小 問題 局部變量 調用 字節 兩種 操作 讀取 定義

轉載請註明作者與出處

程序計數器

線程私有

因為物理cpu並不多,所以jvm是對java裏面的線程進行不停的切換執行,因為切換的執行速度太快,所以我們看到是並發執行。所以jvm在切換線程執行後,如果要切換回原來的線程,它需要記住這個線程的執行位置,下一條指令是什麽。所以每一個線程都有一個獨立的程序計數器,它是線程私有的。

數據內容

程序計數器保存了每個對象的引用數量,但是也不僅僅是對象的引用,它保存了一個線程中一系列需要執行的字節碼指令的內存地址,包括循環,異常等

native方法

如果當前正在執行的是native方法,那麽它在程序計數器裏面的值是空(undefined)。

java棧

線程私有

java棧保存的是執行每一個方法的內容,所以每執行一個方法,都會創建一個棧幀(StackFrame),保存局部變量,操作數棧,動態鏈接,方法的進出信息等,直到一個方法調用完成,就意味著一個棧幀從進去到出來的過程,所以它也是線程私有的。

數據內容

java棧幀中,保存了當前局部的基本數據類型(boolean,byte,char,short,int,float,long,double),以及對象引用

對象引用,這裏指的是定義的那些對象,但是值得註意的是,這裏保存的是引用,而不是具體的內容,當我們new一個對象時,jvm會把創建的引用放在棧裏面,但是對象本身,是存在堆裏面的,而引用只是保存了對象在堆裏面的內存地址,這是因為棧內存很小,但是棧讀取數據快,所以存儲了引用,而我們開辟出來的對象,或者申請的內存是放在堆裏面的。

局部變量所需要的內存,在一開始就是確定的,jvm會按照變量類型計算。因為當進入一個棧幀時,所需要的內存是確定的,直到出棧,這裏面的內存不會發生任何變化。

棧異常

jvm中對於棧規則了兩種異常。

  1. 當java類中的方法進入次數太多時,會導致棧的層次越來越深,如果請求的棧深度,超出了jvm虛擬機所允許的深度,就會拋出StackOverflowError異常。(當前絕大部分虛擬機都是可以動態調整棧深度的,所以一般不會出現這個問題,但是也不排除,因為jvm規範中也允許固定長度的棧深度)
  2. 另一方面,如果擴展棧深度時,無法申請到足夠的內存,就會拋出OutOfMemoryError異常。

所以當我們遍歷文件夾的時候,最好不要用遞歸,因為可能出現棧溢出的異常。

本地方法棧

本地方法棧所起的作用和java棧的作用幾乎一致,只不過本地方法棧中,保存的是native方法的棧信息,但是虛擬機規範中,對於native方法的實現語言,實現類型,數據結構並沒有明確規定,各種虛擬機可以自由實現它,比如Sun HotSpot虛擬機就把java棧和本地方法棧合二為一了。

本地方法棧也有著StackOverflowErrorOutOfMemoryError

java堆

堆是所有線程共享的,它是jvm管理內存的最大的一塊區域,也是java程序員所能操控的內存區域。

數據內容

java程序員所能操控的內存,雖然對於程序員來說沒有感知,但實際上全部是在堆裏面操作,比如我們new出來的對象,以及數組,其實都是存放在堆內存裏面的。

垃圾回收

java堆是gc回收內存的主要區域,因為現在的內存回收算法基本都是采用分代算法,所以還可以分為新生代和老生代,這樣的分配是為了更快的找出需要回收的內存,提高gc效率。甚至還可以更往細分Eden,From Survivor,To Survivor等。

空間大小

java堆裏面的內存可以是物理上不連續的內存,只要是邏輯上連續就可以,一般主流虛擬機,都是可以在啟動的時候,根據啟動參數指定內存大小(-Xms -Xmx),如果在使用內存時,jvm無法再申請新的堆內存,就會拋出OutOfMemoryError異常。

方法區

方法區是所有線程共享的區域,方法區也叫永久代,因為它永遠不會被gc回收。

數據內容

用於存儲虛擬機加載的類信息,常量,靜態變量等數據,這些數據是在類加載器加載時候完成的,所以雖然說new出來的對象是存在堆裏面的,但是如果這個對象是常量,那麽在類加載器加載這個類的時候,就會把這些靜態變量存儲到方法區裏面去。

異常信息

同樣的,方法區的內存無法滿足內存的根本需求時,拋出OutOfMemoryError異常

堆外內存(直接內存)

堆外內存是一塊獨立的內存,值得註意的是,它是由java程序員完全操縱的一個內存,意味著,程序員需要顯式的申請內存,以及手動釋放內存,因為它不由gc管理。

它的優點是因為直接操作內存,在某些應用場景中,可以避免內存的復制,以及回收再創建,可以提升內存的利用率。

它的缺點就是需要手動釋放內存,而不是交給gc來處理,所以使用不當,很容易拋出OutOfMemoryError異常。

堆外內存不受到堆內存的限制,也就是不受到-Xmx的限制,但是還是受到物理內存的限制,如果超出物理內存,就就會拋出OutOfMemoryError

了解java內存模型,看這裏就夠了