了解java內存模型,看這裏就夠了
轉載請註明作者與出處
程序計數器
線程私有
因為物理cpu並不多,所以jvm是對java裏面的線程進行不停的切換執行,因為切換的執行速度太快,所以我們看到是並發執行。所以jvm在切換線程執行後,如果要切換回原來的線程,它需要記住這個線程的執行位置,下一條指令是什麽。所以每一個線程都有一個獨立的程序計數器,它是線程私有的。
數據內容
程序計數器保存了每個對象的引用數量,但是也不僅僅是對象的引用,它保存了一個線程中一系列需要執行的字節碼指令的內存地址,包括循環,異常等
native方法
如果當前正在執行的是native方法,那麽它在程序計數器裏面的值是空(undefined
)。
java棧
線程私有
java棧保存的是執行每一個方法的內容,所以每執行一個方法,都會創建一個棧幀(StackFrame),保存局部變量,操作數棧,動態鏈接,方法的進出信息等,直到一個方法調用完成,就意味著一個棧幀從進去到出來的過程,所以它也是線程私有的。
數據內容
java棧幀中,保存了當前局部的基本數據類型(boolean,byte,char,short,int,float,long,double),以及對象引用。
對象引用,這裏指的是定義的那些對象,但是值得註意的是,這裏保存的是引用,而不是具體的內容,當我們new一個對象時,jvm會把創建的引用放在棧裏面,但是對象本身,是存在堆裏面的,而引用只是保存了對象在堆裏面的內存地址,這是因為棧內存很小,但是棧讀取數據快,所以存儲了引用,而我們開辟出來的對象,或者申請的內存是放在堆裏面的。
局部變量所需要的內存,在一開始就是確定的,jvm會按照變量類型計算。因為當進入一個棧幀時,所需要的內存是確定的,直到出棧,這裏面的內存不會發生任何變化。
棧異常
jvm中對於棧規則了兩種異常。
- 當java類中的方法進入次數太多時,會導致棧的層次越來越深,如果請求的棧深度,超出了jvm虛擬機所允許的深度,就會拋出
StackOverflowError
異常。(當前絕大部分虛擬機都是可以動態調整棧深度的,所以一般不會出現這個問題,但是也不排除,因為jvm規範中也允許固定長度的棧深度) - 另一方面,如果擴展棧深度時,無法申請到足夠的內存,就會拋出
OutOfMemoryError
異常。
所以當我們遍歷文件夾的時候,最好不要用遞歸,因為可能出現棧溢出的異常。
本地方法棧
本地方法棧所起的作用和java棧的作用幾乎一致,只不過本地方法棧中,保存的是native方法的棧信息,但是虛擬機規範中,對於native方法的實現語言,實現類型,數據結構並沒有明確規定,各種虛擬機可以自由實現它,比如Sun HotSpot虛擬機就把java棧和本地方法棧合二為一了。
本地方法棧也有著StackOverflowError
和OutOfMemoryError
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內存模型,看這裏就夠了