摘要:作為一個程序員,不了解內(nèi)存模型就不能寫出能夠充分利用內(nèi)存的代碼。程序計數(shù)器是在電腦處理器中的一個寄存器,用來指示電腦下一步要運行的指令序列。在虛擬機中,本地方法棧和虛擬機棧是共用同一塊內(nèi)存的,不做具體區(qū)分。
作為一個 Java 程序員,不了解 Java 內(nèi)存模型就不能寫出能夠充分利用內(nèi)存的代碼。本文通過對 Java 內(nèi)存模型的介紹,讓讀者能夠了解 Java 的內(nèi)存的分配情況,適合 Java 初學者或者對 JMM 不熟悉的同學。后面的博客會針對每個部分做更加深入的解釋。
Java 內(nèi)存模型首先通過下圖對于 Java 內(nèi)存模型有一個整體的認識,然后針對不同的區(qū)域的作用和存儲的內(nèi)容做進一步的解釋。
PC(程序計數(shù)器)這里的 PC 不是 Personal Computer,而是 Program Counter Register,從名字就可以看出來,這是一個寄存器,用來存儲需要執(zhí)行的指令地址。
程序計數(shù)器(Program Counter (PC))是在電腦處理器中的一個寄存器,用來指示電腦下一步要運行的指令序列。--WikiPedia
PC 和其他 JVM 內(nèi)存區(qū)域最大的區(qū)別是:
“此內(nèi)存區(qū)域是唯一一個在Java虛擬機規(guī)范中沒有規(guī)定任何OutOfMemoryError情況的區(qū)域。”
摘錄來自: 周志明. “深入理解Java虛擬機:JVM高級特性與最佳實踐(第2版)”。 iBooks.
像上面的圖片一樣,PC 是每個線程私有的,對于 Java 方法而言,PC 中存儲的是正在執(zhí)行的虛擬機字節(jié)碼的內(nèi)存地址;對于 Native 方法來說,PC 中的值為空(Undefined)。
Java 虛擬機棧和本地方法棧 虛擬機棧無論是在大學的 Java 編程課堂上,還是我們在學習過程編碼過程,經(jīng)常會出現(xiàn) StackOverFlow,甚至目前最大的技術問答社區(qū)的名字也是 StackOverFlow。Java 語言中會產(chǎn)生棧溢出的就是這塊內(nèi)存區(qū)域,當你的程序中設置了超過 JVM 規(guī)定的遞歸深度的時候就會觸發(fā)這個異常。類似 JMM 的其他內(nèi)存區(qū)域,如果虛擬機棧在動態(tài)擴展的時候無法申請到足夠的內(nèi)存也會報OOM異常。
Java 語言中每一個方法的執(zhí)行都對應著一個棧幀(Stack Frame)的創(chuàng)建,棧幀中存儲的是局部變量、方法出口等信息,因此對于一個方法的執(zhí)行而言,所能夠使用到的內(nèi)存是在編譯期間就能夠完全確定的,在運行期間不會發(fā)生變化。在棧幀中,局部變量空間成為 Slot,除了 double 和 long 占有 2 個 slot 外,其他基本數(shù)據(jù)類型和對象引用都占用 1 個 slot 空間
本地方法棧本地方法棧和虛擬機棧最大的區(qū)別就是虛擬機棧是為執(zhí)行 Java 字節(jié)碼服務的,而本地方法棧是為了虛擬機使用到的 Native 方法服務的。除此之外,Java 虛擬機規(guī)范并沒有針對本地方法棧的實現(xiàn)做具體規(guī)定。在 HotSpot 虛擬機中,本地方法棧和虛擬機棧是共用同一塊內(nèi)存的,不做具體區(qū)分。同樣,本地方法棧也會產(chǎn)生 OOM 異常和 StackOverFlow 異常。
Java 堆“The heap is the runtime data area from which memory for all class instances and arrays is allocated。” --Java虛擬機規(guī)范
Java 虛擬機規(guī)范規(guī)定所有的實例對象和數(shù)組都應該分配到 Java 堆中。
說的通俗一點就是所有 new 出來的對象和數(shù)組都會放到該區(qū)域,由于現(xiàn)在的收集器都采用分代收集算法,所以在 Java 堆中又分了新生代和老年代,新生代有做了詳細的區(qū)分。該區(qū)域的大小可以通過 JVM 參數(shù) -Xmx 和 -Xms 來設置。
在 JDK1.4 中引入了 NIO,可以通過 Native 方法直接在堆外分配內(nèi)存,然后通過在堆中存儲的引用來對這塊內(nèi)存區(qū)域做操作。注意 這塊區(qū)域并不會在 -Xmx和 -Xms 設置的大小之內(nèi),因此在設置 JVM 參數(shù)的時候要注意考慮這塊內(nèi)存區(qū)域,避免設置的內(nèi)存區(qū)域總額大于物理內(nèi)存
方法區(qū)Method Area 又叫 NonHeap,也是線程共有的內(nèi)存區(qū)域,用來存:
類信息
常量
靜態(tài)變量
字符串常量池
在 JDK1.7 中已經(jīng)將字符串常量池移出永久代,在 Java8 中更是之內(nèi)取消了永久代,而是使用了元空間(MetaSpace)來存儲這些信息,從而永久代的大小不需要再制定,只要不超出物理內(nèi)存的限制就不會產(chǎn)生 OOM 異常
運行時常量池運行時常量池主要用來存儲累的版本、字段、方法、接口等描述信息。常量池(Constant Pool Table)用來存儲各種字面量和符號引用。String 的 intern() 方法就是在運行期間將對象放到常量池中的。此部分也會出現(xiàn) OOM 異常。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/69540.html
摘要:內(nèi)存模型首先介紹下程序具體執(zhí)行的過程源代碼文件后綴會被編譯器編譯為字節(jié)碼文件后綴由中的類加載器加載各個類的字節(jié)碼文件,加載完畢之后,交由執(zhí)行引擎執(zhí)行在整個程序執(zhí)行過程中,會用一段空間來存儲程序執(zhí)行期間需要用到的數(shù)據(jù)和相關信息,這段空間一般被 [TOC] JVM內(nèi)存模型 首先介紹下Java程序具體執(zhí)行的過程: Java源代碼文件(.java后綴)會被Java編譯器編譯為字節(jié)碼文件(....
摘要:基礎問題的的性能及原理之區(qū)別詳解備忘筆記深入理解流水線抽象關鍵字修飾符知識點總結(jié)必看篇中的關鍵字解析回調(diào)機制解讀抽象類與三大特征時間和時間戳的相互轉(zhuǎn)換為什么要使用內(nèi)部類對象鎖和類鎖的區(qū)別,,優(yōu)缺點及比較提高篇八詳解內(nèi)部類單例模式和 Java基礎問題 String的+的性能及原理 java之yield(),sleep(),wait()區(qū)別詳解-備忘筆記 深入理解Java Stream流水...
摘要:基礎問題的的性能及原理之區(qū)別詳解備忘筆記深入理解流水線抽象關鍵字修飾符知識點總結(jié)必看篇中的關鍵字解析回調(diào)機制解讀抽象類與三大特征時間和時間戳的相互轉(zhuǎn)換為什么要使用內(nèi)部類對象鎖和類鎖的區(qū)別,,優(yōu)缺點及比較提高篇八詳解內(nèi)部類單例模式和 Java基礎問題 String的+的性能及原理 java之yield(),sleep(),wait()區(qū)別詳解-備忘筆記 深入理解Java Stream流水...
閱讀 4556·2021-11-24 10:24
閱讀 1470·2021-11-22 15:22
閱讀 2158·2021-11-17 09:33
閱讀 2548·2021-09-22 15:29
閱讀 571·2019-08-30 15:55
閱讀 1715·2019-08-29 18:42
閱讀 2788·2019-08-29 12:55
閱讀 1834·2019-08-26 13:55