JVM-01Java内存区域与内存溢出异常(上)【运行时区域数据】
- 思維導(dǎo)圖
- 概述
- 運(yùn)行時(shí)數(shù)據(jù)區(qū)域
- 程序計(jì)數(shù)器 (Program Counter Register)
- 概念
- 特征
- 可能拋出的異常
- 知識擴(kuò)展:JIT即時(shí)編譯
- Java虛擬機(jī)棧 (Java Virtual Machine Stacks)
- 概念
- 特性
- 可能拋出的異常
- 虛擬機(jī)棧的StackOverflowError
- 虛擬機(jī)棧的OutOfMemoryError
- 本地方法棧
- 和虛擬機(jī)棧的區(qū)別
- 特性
- Java堆
- 堆的分層
- 新生代
- 老年代 (主要存放應(yīng)用程序中生命周期長的內(nèi)存對象。)
- GC 回收機(jī)制
- 新生代Minor GC
- 老年代Full GC(或者叫Major GC)
- JVM參數(shù)
- 方法區(qū)(永久代)
- 運(yùn)行時(shí)常量池(屬于方法區(qū))
- 直接內(nèi)存
- 程序計(jì)數(shù)器 (Program Counter Register)
思維導(dǎo)圖
概述
在內(nèi)存管理領(lǐng)域 ,C/C++內(nèi)存管理由開發(fā)人員管理,既擁有每一個(gè)對象的所有權(quán),還必須負(fù)責(zé)維護(hù)每一個(gè)對象生命從開始到終結(jié)的責(zé)任
對于Java開發(fā)人員來講,在虛擬機(jī)自動(dòng)內(nèi)存管理機(jī)制的幫助下,Java由虛擬機(jī)管理內(nèi)存,不容易出現(xiàn)內(nèi)存泄露和內(nèi)存溢出,一旦出現(xiàn)如果不了解JVM很難排查。
這里我們主要介紹虛擬機(jī)內(nèi)存的各個(gè)區(qū)域,講解這些區(qū)域的作用、服務(wù)對象以及可能產(chǎn)生的問題。
Java虛擬機(jī)(JVM)在Java程序運(yùn)行的過程中,會(huì)將它所管理的內(nèi)存劃分為若干個(gè)不同的數(shù)據(jù)區(qū)域,這些區(qū)域有的隨著JVM的啟動(dòng)而創(chuàng)建,有的隨著用戶線程的啟動(dòng)和結(jié)束而建立和銷毀。
一個(gè)基本的JVM運(yùn)行時(shí)內(nèi)存模型如下
上圖是基于“JAVA SE7”的JVM虛擬機(jī)規(guī)范。虛擬機(jī)規(guī)范并非一成不變,比如在JDK8的版本中,方法區(qū)被移除,取而代之的是元數(shù)據(jù)空間metaspace。
運(yùn)行時(shí)數(shù)據(jù)區(qū)域
程序計(jì)數(shù)器 (Program Counter Register)
概念
程序計(jì)數(shù)器 (Program Counter Register)是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號指示器。
JAVA代碼編譯后的字節(jié)碼在未經(jīng)過JIT(實(shí)時(shí)編譯器)編譯前,其執(zhí)行方式是通過“字節(jié)碼解釋器”進(jìn)行解釋執(zhí)行。簡單的工作原理為解釋器讀取裝載入內(nèi)存的字節(jié)碼,按照順序讀取字節(jié)碼指令。讀取一個(gè)指令后,將該指令“翻譯”成固定的操作,并根據(jù)這些操作進(jìn)行分支、循環(huán)、跳轉(zhuǎn)等流程。
假設(shè)程序永遠(yuǎn)只有一個(gè)線程,并不需要程序計(jì)數(shù)器。但實(shí)際上程序是通過多個(gè)線程協(xié)同合作執(zhí)行的.
Java虛擬機(jī)的多線程是通過線程輪流切換并分配處理器執(zhí)行時(shí)間的方式實(shí)現(xiàn)的。
JVM的多線程是通過CPU時(shí)間片輪轉(zhuǎn)(即線程輪流切換并分配處理器執(zhí)行時(shí)間)算法來實(shí)現(xiàn)的。
也就是說,某個(gè)線程在執(zhí)行過程中可能會(huì)因?yàn)闀r(shí)間片耗盡而被掛起,而另一個(gè)線程獲取到時(shí)間片開始執(zhí)行。
當(dāng)被掛起的線程重新獲取到時(shí)間片的時(shí)候,它要想從被掛起的地方繼續(xù)執(zhí)行,就必須知道它上次執(zhí)行到哪個(gè)位置,在JVM中,通過程序計(jì)數(shù)器來記錄某個(gè)線程的字節(jié)碼執(zhí)行位置。
因此,程序計(jì)數(shù)器是具備線程隔離的特性,也就是說,每個(gè)線程工作時(shí)都有屬于自己的獨(dú)立計(jì)數(shù)器。
特征
線程隔離性,每個(gè)線程工作時(shí)都有屬于自己的獨(dú)立計(jì)數(shù)器。
執(zhí)行java方法時(shí),程序計(jì)數(shù)器是有值的,且記錄的是正在執(zhí)行的字節(jié)碼指令的地址
執(zhí)行native本地方法時(shí),程序計(jì)數(shù)器的值為空(Undefined)。因?yàn)閚ative方法是java通過JNI直接調(diào)用本地C/C++庫,由于該方法是通過C/C++而不是java進(jìn)行實(shí)現(xiàn)。所以無法產(chǎn)生相應(yīng)的字節(jié)碼,并且C/C++執(zhí)行時(shí)的內(nèi)存分配是由自己語言決定的,而不是由JVM決定的。
程序計(jì)數(shù)器占用內(nèi)存很小,在進(jìn)行JVM內(nèi)存計(jì)算時(shí),可以忽略不計(jì)
- 程序計(jì)數(shù)器是唯一一個(gè)在java虛擬機(jī)規(guī)范中沒有規(guī)定任何OutOfMemoryError的區(qū)域。
可能拋出的異常
程序計(jì)數(shù)器是唯一一個(gè)在java虛擬機(jī)規(guī)范中沒有規(guī)定任何OutOfMemoryError的區(qū)域。
知識擴(kuò)展:JIT即時(shí)編譯
許多主流的商用虛擬機(jī)(如HotSpot),都同時(shí)包含解釋器和編譯器。
Java程序最初是僅僅通過解釋器解釋執(zhí)行的,即對字節(jié)碼逐條解釋執(zhí)行,這種方式的執(zhí)行速度相對會(huì)比較慢,
尤其當(dāng)某個(gè)方法或代碼塊運(yùn)行的特別頻繁時(shí),這種方式的執(zhí)行效率就顯得很低。
于是后來在虛擬機(jī)中引入了JIT編譯器(即時(shí)編譯器),當(dāng)虛擬機(jī)發(fā)現(xiàn)某個(gè)方法或代碼塊運(yùn)行特別頻繁時(shí),就會(huì)把這些代碼認(rèn)定為“Hot Spot Code”(熱點(diǎn)代碼),為了提高熱點(diǎn)代碼的執(zhí)行效率,在運(yùn)行時(shí),虛擬機(jī)將會(huì)把這些代碼編譯成與本地平臺相關(guān)的機(jī)器碼,并進(jìn)行各層次的優(yōu)化,完成這項(xiàng)任務(wù)的正是JIT編譯器。
- 當(dāng)程序需要迅速啟動(dòng)和執(zhí)行時(shí),解釋器可以首先發(fā)揮作用,省去編譯的時(shí)間,立即執(zhí)行;
- 當(dāng)程序運(yùn)行后,隨著時(shí)間的推移,編譯器逐漸會(huì)失去作用,把越來越多的代碼編譯成本地代碼后,可以獲取更高的執(zhí)行效率。
- 解釋執(zhí)行可以節(jié)約內(nèi)存,而編譯執(zhí)行可以提升效率。
Java虛擬機(jī)棧 (Java Virtual Machine Stacks)
概念
同程序計(jì)數(shù)器一樣,虛擬機(jī)棧也是線程私有的,生命周期同線程相同。
虛擬機(jī)棧描述的是java方法執(zhí)行的內(nèi)存模型: 每個(gè)java方法在執(zhí)行時(shí),會(huì)創(chuàng)建一個(gè)“棧幀(stack frame)”,棧幀的結(jié)構(gòu)分為“局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈接、方法出口”幾個(gè)部分。
我們常說的“堆內(nèi)存、棧內(nèi)存”中的“棧內(nèi)存”指的便是虛擬機(jī)棧,確切地說,指的是虛擬機(jī)棧的棧幀中的局部變量表,因?yàn)檫@里存放了一個(gè)方法的所有局部變量。
局部變量表所需的內(nèi)存空間在編譯期間完成分配。在方法運(yùn)行的階段是不會(huì)改變局部變量表的大小的。
方法調(diào)用時(shí),創(chuàng)建棧幀,并壓入虛擬機(jī)棧;方法執(zhí)行完畢,棧幀出棧并被銷毀
特性
虛擬機(jī)棧是線程隔離的,即每個(gè)線程都有自己獨(dú)立的虛擬機(jī)棧。
后進(jìn)先出(LIFO)棧
存儲(chǔ)棧幀,支撐java方法的調(diào)用執(zhí)行和退出
可能出現(xiàn)OutOfMemoryError異常和StackOverflowError異常
可能拋出的異常
虛擬機(jī)棧的StackOverflowError
若單個(gè)線程請求的棧深度大于虛擬機(jī)允許的深度,則會(huì)拋出StackOverflowError(棧溢出錯(cuò)誤)。
JVM會(huì)為每個(gè)線程的虛擬機(jī)棧分配一定的內(nèi)存大小(-Xss參數(shù)),因此虛擬機(jī)棧能夠容納的棧幀數(shù)量是有限的,若棧幀不斷進(jìn)棧而不出棧,最終會(huì)導(dǎo)致當(dāng)前線程虛擬機(jī)棧的內(nèi)存空間耗盡,典型如一個(gè)無結(jié)束條件的遞歸函數(shù)調(diào)用
虛擬機(jī)棧的OutOfMemoryError
不同于StackOverflowError,OutOfMemoryError指的是當(dāng)整個(gè)虛擬機(jī)棧內(nèi)存耗盡,并且無法再申請到新的內(nèi)存時(shí)拋出的異常。
JVM未提供設(shè)置整個(gè)虛擬機(jī)棧占用內(nèi)存的配置參數(shù)。虛擬機(jī)棧的最大內(nèi)存大致上等于“JVM進(jìn)程能占用的最大內(nèi)存(依賴于具體操作系統(tǒng)) - 最大堆內(nèi)存 - 最大方法區(qū)內(nèi)存 - 程序計(jì)數(shù)器內(nèi)存(可以忽略不計(jì)) - JVM進(jìn)程本身消耗內(nèi)存”。當(dāng)虛擬機(jī)棧能夠使用的最大內(nèi)存被耗盡后,便會(huì)拋出OutOfMemoryError,可以通過不斷開啟新的線程來模擬這種異常
本地方法棧
和虛擬機(jī)棧的區(qū)別
本地方法棧(Native Method Stack)與虛擬機(jī)棧所發(fā)揮的作用非常相似,它們之間的區(qū)別是虛擬機(jī)棧為虛擬機(jī)執(zhí)行Java方法服務(wù),而本地方法棧則為虛擬機(jī)使用到的Native方法服務(wù)。
在虛擬機(jī)規(guī)范中對本地方法棧中方法使用的語言,使用方法與數(shù)據(jù)結(jié)構(gòu)沒有強(qiáng)制規(guī)定,因此具體的虛擬機(jī)可以自由的實(shí)現(xiàn)它。甚至有的虛擬機(jī)(比如Sun HotSpot虛擬機(jī))直接把本地方法棧和虛擬機(jī)合二為一。
本地方法:該方法的實(shí)現(xiàn)由非java語言實(shí)現(xiàn),比如C語言實(shí)現(xiàn)
與虛擬機(jī)一樣,本地方法棧區(qū)域也會(huì)拋出StackOverflowError和OutOfMemoryErrory異常。
特性
線程私有
后進(jìn)先出(LIFO)棧
存儲(chǔ)棧幀,支撐本地方法的調(diào)用執(zhí)行和退出
可能出現(xiàn)OutOfMemoryError異常和StackOverflowError異常
有一些虛擬機(jī)(如HotSpot)將java虛擬機(jī)棧和本地方法棧合并實(shí)現(xiàn)
Java堆
Java堆是Java虛擬機(jī)所管理的內(nèi)存中最大的一塊數(shù)據(jù)區(qū)域,在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建并被所有線程共享。
此內(nèi)存區(qū)域唯一的目的就是存放對象實(shí)例,幾乎所有的對象實(shí)例都在這里分配內(nèi)存,例如對象實(shí)例和數(shù)組。
但隨著其他技術(shù)的成熟(如JIT),對象分配在堆上慢慢地變得又沒那么“絕對”了。
Java堆同樣是垃圾收集器管理的主要區(qū)域,由于現(xiàn)在的收集器基本都采用分代收集算法,所以Java堆中還可以細(xì)分為新生代和老年代。
當(dāng)前主流的虛擬機(jī)都是按照可擴(kuò)展來實(shí)現(xiàn)的(通過-Xmx和-Xms控制)。如果堆中沒有內(nèi)存完成實(shí)例分配,并且對也無法再擴(kuò)展時(shí),將會(huì)拋出OutOfMemoryError異常。
堆的分層
HotSpot JVM中的堆,一般分為:新生代、老年代
默認(rèn)的,新生代 ( Young ) 與老年代 ( Old ) 的比例的值為 1:2 ( 該值可以通過參數(shù) –XX:NewRatio 來指定 ),即:新生代 ( Young ) = 1/3 的堆空間大小。老年代 ( Old ) = 2/3 的堆空間大小。
新生代
新生代又分為 Eden區(qū)、SurvivorFrom、SurvivorTo三個(gè)區(qū)
默認(rèn)的,Edem : from : to = 8 : 1 : 1 ( 可以通過參數(shù) –XX:SurvivorRatio 來設(shè)定 ),即: Eden = 8/10 的新生代空間大小,from = to = 1/10 的新生代空間大小。
JVM 每次只會(huì)使用 Eden 和其中的一塊 Survivor 區(qū)域來為對象服務(wù),所以無論什么時(shí)候,總是有一塊 Survivor 區(qū)域是空閑著的。
因此,新生代實(shí)際可用的內(nèi)存空間為 9/10 ( 即90% )的新生代空間,只有10%的內(nèi)存被“浪費(fèi)”,最大限度的節(jié)約資源。
老年代 (主要存放應(yīng)用程序中生命周期長的內(nèi)存對象。)
老年代的對象比較穩(wěn)定,所以MajorGC不會(huì)頻繁執(zhí)行。在進(jìn)行MajorGC前一般都先進(jìn)行了一次MinorGC,使得有新生代的對象晉身入老年代,導(dǎo)致空間不夠用時(shí)才觸發(fā)。當(dāng)無法找到足夠大的連續(xù)空間分配給新創(chuàng)建的較大對象時(shí)也會(huì)提前觸發(fā)一次MajorGC進(jìn)行垃圾回收騰出空間。
MajorGC采用標(biāo)記—清除算法:首先掃描一次所有老年代,標(biāo)記出存活的對象,然后回收沒有標(biāo)記的對象。MajorGC的耗時(shí)比較長,因?yàn)橐獟呙柙倩厥铡ajorGC會(huì)產(chǎn)生內(nèi)存碎片,為了減少內(nèi)存損耗,我們一般需要進(jìn)行合并或者標(biāo)記出來方便下次直接分配。
當(dāng)老年代也滿了裝不下的時(shí)候,就會(huì)拋出OOM(Out of Memory)異常。
GC 回收機(jī)制
Java 中的堆也是 GC 收集垃圾的主要區(qū)域。GC 分為兩種:Minor GC、Full GC ( 或稱為 Major GC )。
新生代Minor GC
Minor GC 是發(fā)生在新生代中的垃圾收集動(dòng)作,所采用的是復(fù)制算法。
新生代幾乎是所有 Java 對象出生的地方,即 Java 對象申請的內(nèi)存以及存放都是在這個(gè)地方。Java 中的大部分對象通常不需長久存活,具有朝生夕滅的性質(zhì)。
當(dāng)對象在 Eden ( 包括一個(gè) Survivor 區(qū)域,這里假設(shè)是 from 區(qū)域 ) 出生后,在經(jīng)過一次 Minor GC 后,如果對象還存活,并且能夠被另外一塊 Survivor 區(qū)域所容納( 上面已經(jīng)假設(shè)為 from 區(qū)域,這里應(yīng)為 to 區(qū)域,即 to 區(qū)域有足夠的內(nèi)存空間來存儲(chǔ) Eden 和 from 區(qū)域中存活的對象 ),則使用復(fù)制算法將這些仍然還存活的對象復(fù)制到另外一塊 Survivor 區(qū)域 ( 即 to 區(qū)域 ) 中,然后清理所使用過的 Eden 以及 Survivor 區(qū)域 ( 即 from 區(qū)域 ),并且將這些對象的年齡設(shè)置為1,以后對象在 Survivor 區(qū)每熬過一次 Minor GC,就將對象的年齡 + 1,當(dāng)對象的年齡達(dá)到某個(gè)值時(shí) ( 默認(rèn)是 15 歲,可以通過參數(shù) -XX:MaxTenuringThreshold 來設(shè)定 ),這些對象就會(huì)成為老年代。
但這也不是一定的,對于一些較大的對象 ( 即需要分配一塊較大的連續(xù)內(nèi)存空間 ) 則是直接進(jìn)入到老年代。
老年代Full GC(或者叫Major GC)
Full GC 是發(fā)生在老年代的垃圾收集動(dòng)作,所采用的是標(biāo)記-清除算法。
堆內(nèi)存中的老年代(Old)不同于這個(gè),老年代里面的對象幾乎個(gè)個(gè)都是在 Survivor 區(qū)域中熬過來的,它們是不會(huì)那么容易就 “死掉” 了的。因此,Full GC 發(fā)生的次數(shù)不會(huì)有 Minor GC 那么頻繁,并且做一次 Full GC 要比進(jìn)行一次 Minor GC 的時(shí)間更長。
另外,標(biāo)記-清除算法收集垃圾的時(shí)候會(huì)產(chǎn)生許多的內(nèi)存碎片 ( 即不連續(xù)的內(nèi)存空間 ),此后需要為較大的對象分配內(nèi)存空間時(shí),若無法找到足夠的連續(xù)的內(nèi)存空間,就會(huì)提前觸發(fā)一次 GC 的收集動(dòng)作。
JVM參數(shù)
官網(wǎng) :http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html
如下僅列舉幾個(gè)常用的
| -Xms | 初始堆大小。如:-Xms256m |
| -Xmx | 最大堆大小。如:-Xmx512m |
| -Xmn | 新生代大小。通常為 Xmx 的 1/3 或 1/4。新生代 = Eden + 2 個(gè) Survivor 空間。實(shí)際可用空間為 = Eden + 1 個(gè) Survivor,即 90% |
| -Xss | JDK1.5+ 每個(gè)線程堆棧大小為 1M,一般來說如果棧不是很深的話, 1M 是絕對夠用了的。 |
| -XX:NewRatio | 新生代與老年代的比例,如 –XX:NewRatio=2,則新生代占整個(gè)堆空間的1/3,老年代占2/3 |
| -XX:SurvivorRatio | 新生代中 Eden 與 Survivor 的比值。默認(rèn)值為 8。即 Eden 占新生代空間的 8/10,另外兩個(gè) Survivor 各占 1/10 |
| -XX:PermSize | 永久代(方法區(qū))的初始大小 |
| -XX:MaxPermSize | 永久代(方法區(qū))的最大值 |
| -XX:+PrintGCDetails | 打印 GC 信息 |
| -XX:+HeapDumpOnOutOfMemoryError | 讓虛擬機(jī)在發(fā)生內(nèi)存溢出時(shí) Dump 出當(dāng)前的內(nèi)存堆轉(zhuǎn)儲(chǔ)快照,以便分析用 |
方法區(qū)(永久代)
方法區(qū)(Method Area)與Java堆一樣,是各個(gè)線程共享的內(nèi)存區(qū)域,它用于存儲(chǔ)已被虛擬機(jī)加載的類信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼等數(shù)據(jù)。
方法區(qū)也稱Non-Heap(非堆),目的是與Java堆區(qū)分開來,可通過-XX:MaxPermSize設(shè)置內(nèi)存大小。
從JVM運(yùn)行時(shí)區(qū)域內(nèi)存模型來看,堆和方法區(qū)是兩塊獨(dú)立的內(nèi)存塊。但從垃圾收集器來看,HotSpot虛擬機(jī)的設(shè)計(jì)團(tuán)隊(duì)選擇把GC分代收集擴(kuò)展至方法區(qū),或者說使用永久代來實(shí)現(xiàn)方法區(qū),所以很多人都更愿意把方法區(qū)稱為“永久代”
指內(nèi)存的永久保存區(qū)域,主要存放Class和Meta(元數(shù)據(jù))的信息,Class在被加載的時(shí)候被放入永久區(qū)域. 它和和存放實(shí)例的區(qū)域不同,GC不會(huì)在主程序運(yùn)行期對永久區(qū)域進(jìn)行清理。所以這也導(dǎo)致了永久代的區(qū)域會(huì)隨著加載的Class的增多而脹滿,最終拋出OOM異常。
在Java8中,永久代已經(jīng)被移除,被一個(gè)稱為“元數(shù)據(jù)區(qū)”(元空間)的區(qū)域所取代。
元空間的本質(zhì)和永久代類似,都是對JVM規(guī)范中方法區(qū)的實(shí)現(xiàn)。不過元空間與永久代之間最大的區(qū)別在于:元空間并不在虛擬機(jī)中,而是使用本地內(nèi)存。
因此,默認(rèn)情況下,元空間的大小僅受本地內(nèi)存限制。類的元數(shù)據(jù)放入 native memory, 字符串池和類的靜態(tài)變量放入java堆中. 這樣可以加載多少類的元數(shù)據(jù)就不再由MaxPermSize控制, 而由系統(tǒng)的實(shí)際可用空間來控制.
運(yùn)行時(shí)常量池(屬于方法區(qū))
運(yùn)行時(shí)常量池(Runtime Constant Pool)是方法區(qū)的一部分,用于存放Class文件在編譯期生成的各種字面量和符號引用.
因?yàn)镃lass文件除了有類的版本、字段、方法、接口等描述信息外,還有一項(xiàng)信息是常量池(Constant Pool Table)。這部分內(nèi)容將在類加載后進(jìn)入方法區(qū)的運(yùn)行時(shí)常量池中存放。同時(shí)運(yùn)行時(shí)常量池具備動(dòng)態(tài)性,并非預(yù)置入Class文件中常量池的內(nèi)存才能進(jìn)入方法區(qū)運(yùn)行時(shí)常量池,運(yùn)行期間也可能將新的常量放入池中,例如String類的inter()方法。既然運(yùn)行時(shí)常量池是方法區(qū)的一部分,自然受到方法區(qū)內(nèi)存限制,當(dāng)常量池?zé)o法再申請到內(nèi)存時(shí)會(huì)拋出OutOfMemoryError異常。
直接內(nèi)存
直接內(nèi)存(Direct Memory)并不是虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)的一部分,也不是Java虛擬機(jī)規(guī)范中定義的內(nèi)存區(qū)域。但是這部分內(nèi)存也被頻繁的使用,而且也可能導(dǎo)致OutOfMemoryError異常出現(xiàn)。
在JDK1.4中新加入了NIO(New Input/Output)類,引入了一種基于通道(channel)與緩沖區(qū)(Buffer)的I/O方式,它可以使用Native函數(shù)庫直接分配堆外內(nèi)存,然后通過一個(gè)存儲(chǔ)在Java堆中的DirectByteBuffer對象作為這塊內(nèi)存區(qū)域的引用進(jìn)行操作。這樣能在一些場景中顯著的提高性能,因?yàn)楸苊饬嗽贘ava堆和Native堆之間來回復(fù)制數(shù)據(jù)。
本機(jī)直接內(nèi)存不會(huì)受Java堆大小的限制,但是,既然是內(nèi)存,那么還是會(huì)受到本機(jī)總的內(nèi)存(包塊RAM以及SWAP區(qū)或者分頁文件)大小以及處理器尋址空間的限制。
服務(wù)器管理人員在配置虛擬機(jī)參數(shù)時(shí),會(huì)根據(jù)實(shí)際內(nèi)存設(shè)置-Xmx等信息參數(shù)信息,但經(jīng)常忽略直接內(nèi)存,使的各個(gè)內(nèi)存區(qū)域總和大于物理內(nèi)存限制從而導(dǎo)致動(dòng)態(tài)擴(kuò)展時(shí)出現(xiàn)OutOfMemoryError異常。
總結(jié)
以上是生活随笔為你收集整理的JVM-01Java内存区域与内存溢出异常(上)【运行时区域数据】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Centos6.5安装/运行/启动/登录
- 下一篇: 修改centos等linux的hostn