前言
JVM與計算機內存設計類似,都有一塊主內存,不過JVM是以線程形式運行。
JVM執行一段代碼流程
1.通過類裝載系統加載字節碼信息存入內存區域中
2.內存中有:方法區,堆區,棧區,本地方法棧,程序計數器
3.運行時數據會加載近內存各個區域中,當然各個區域有各自的職責
4.最后加載進本地方法庫
程序計數器
程序計數器大家可以想象成一個指針,并且每個線程都有一個獨立的程序計數器。這個指針將加載進來的.class文件一行一行的遍歷,也就是每執行一行,指針會索引會增加,當然程序計數器是Java執行代碼塊時重要部件,JVM解釋器就是通過程序計數器解釋一些,循環,跳轉,分支,或者異常處理。并且多線程情況下,線程會根據系統時間片分配搶占資源,當一個線程停止時,程序技術器的指針用來記住代碼執行的位置。當然這就是為什么每個線程都有一個獨立的程序計數器。我們叫做線程獨立。所以大家可以猜想這快區域所分配的內存大小,應該不會很大,對吧?
棧區
StackOverflowError?想必大家見到過這個錯誤吧。
我們由此來介紹下java的棧區,常常有人將JVM內存分為堆區和棧區,這個是很不靠譜的。因為實際虛擬機有5塊區域,正如我們上述講的,方法區,堆區,程序計數器,本地方法棧,棧區。
當然現在大部分人只會注重java虛擬機中的堆區和棧區。因為棧區中存放了java的局部變量。實際上每當一個方法執行時,JVM會分配好一個棧結構。方法的執行就是入棧和出棧的過程。棧中會有:局部變量,方法出口,操作棧,動態鏈接等。我們回歸到剛才的那個錯誤,方法執行時,棧會分配好大小,在編譯期就已經計算好了局部變量的大小。所以如果大小超出了棧的大小就會爆出這個錯誤啦。
本地方法棧
本地方法棧與棧區很類似,但不同的是不執行java方法,而是去執行native方法。當然像sun HotSpot這款虛擬機就將本地方法棧和棧區和為一體。
堆區
這就是我們常說的GC區域,堆區用來存放對象,數組等,是線程共享的區域。所以堆區的的內存是很大啦,不過在大也會OOM。
根據Java 虛擬機規范的規定,Java 堆可以處于物理上不連續的內存空間中,只要邏輯上是連續的即可,就像我們的磁盤空間一樣。在實現時,既可以實現成固定大小的,也可以是可擴展的,不過當前主流的虛擬機都是按照可擴展來實現的(通過-Xmx和-Xms 控制)。
方法區
用于存放類信息,靜態變量,常量,以及編譯后的字節碼信息。
類外方法區中還會有一塊區域是運行時常量區:存放版本信息,字段,方法,借口描述。例如還會有string的串池。
總結:
堆:大部分對象
棧:局部變量
多線程:棧空間獨立,堆空間共享。