深入JAVA虛擬機2_4OutOfMemoryError異常


layout: post

title: 深入JAVA虛擬機2_4OutOfMemoryError異常

categories: JVM JAVA

description: 深入JAVA虛擬機2_4OutOfMemoryError異常

keywords: JVM JAVA

注意:KOTLIN跟JAVA運行結果可能會不同,參照樣例
http://www.reibang.com/p/d9f90f3ee936


2_4_1. JAVA堆溢出測試

測試思路

java堆用于存儲對象實例,只要不斷創(chuàng)建對象邪驮,并保證
GC Roots到對象之間有可達路徑來避免垃圾回收機制清
除這些對象澜躺,那么在對象數(shù)量到達最大堆的容量限制后
就會產(chǎn)生內(nèi)存溢出異常

code2_3虛擬機參數(shù)

//限制java堆的大小為20mb[-Xms為堆的最小值,-Xmx為
堆的最大值]
//XX:+HeapDumpOnOutOfMemoryError可讓虛擬機在出
現(xiàn)內(nèi)存溢出異常時Dump出當前內(nèi)存堆轉儲快照以便事后
進行分析
參數(shù):  -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError

code2_3 代碼

package num2

/**
 * Created by Joey_Tsai on 2018/3/5.
 */
class HeapOOM{
    companion object {
        class OOMObject{

        }
    }
}

fun main(args : Array<String>){
    val list : MutableList<HeapOOM.Companion.OOMObject> = ArrayList<HeapOOM.Companion.OOMObject>();
    var i = 0;
    while (true){
        list.add(HeapOOM.Companion.OOMObject());

        println(++i);
    }
}

內(nèi)存泄漏 與 內(nèi)存溢出

內(nèi)存泄漏:編寫的程序沒有正確的釋放內(nèi)存
內(nèi)存溢出:內(nèi)存不足,無法正常給程序分配內(nèi)存私恬,導致內(nèi)
存不足的原因有很多堪澎,內(nèi)存泄漏只是其中的一種

解決方法

使用工具檢查GC Roots查看引用鏈上的對象是否都有存
活的意義柜裸,若確實沒有出現(xiàn)泄露的情況缕陕,應該調(diào)整堆內(nèi)
存參數(shù)(-Xmx 和 Xms)的最大值和最小值

p.s

程序運行參數(shù)圖

程序運行結果圖

github鏈接(使用kotlin實現(xiàn))
https://github.com/joeytsai03/JVMStudy/blob/master/src/num2/code2_3.kt



                          分    割    線


2_4_2. 虛擬機棧和本地方法棧溢出

1.虛擬機棧和本地方法棧OOM測試

測試思路

HotSpot虛擬機中不分虛擬機棧和本地方法棧,故-Xoss
參數(shù)(設置本地方法棧大小)存在但實際上是無效的疙挺,棧容
量由-Xss參數(shù)設定扛邑,關于虛擬機棧和本地方法棧java虛擬
機描述了兩種異常:
1.如果線程請求的棧深度大于虛擬機所允許的最大深度,
  將拋出StackOverflowError異常
2.如果虛擬機在擴展棧時無法申請到足夠的內(nèi)存空間,則
  拋出OutOfMemoryError異常

code2_4虛擬機參數(shù)

參數(shù) :   -Xss128k

code2_4代碼

package num2

/**
 * Created by Joey_Tsai on 2018/3/5.
 * VM:-Xss128k
 */
public class JavaVMStackSOF{
    public var stackLength : Int = 1
    public fun stackLeak() : Unit{
        stackLength++;
        stackLeak()
    }
}
fun main(args:Array<String>){
    val javaVMStackSOF : JavaVMStackSOF = JavaVMStackSOF()
   try {

       javaVMStackSOF.stackLeak()

   }catch (e : Throwable ){
       println("stack length : ${javaVMStackSOF.stackLength}")
       throw e
   }
}

java虛擬機棧 與 java堆 與 方法區(qū)

1.java虛擬機棧:線程私有,生命周期與線程相同铐然,每個方
法在執(zhí)行的過程中都會創(chuàng)建一個棧幀(Stack Frame)用于
存儲局部變量表蔬崩,操作數(shù)棧,動態(tài)鏈接搀暑,方法出口等信
息沥阳。每一個方法執(zhí)行完成的過程,就對應一個棧幀在虛
擬機棧中入棧出棧的過程自点。

2.java堆:所有線程共享的一塊內(nèi)存區(qū)域桐罕,用于存放對象
實例,垃圾收集器管理的主要區(qū)域桂敛,很多時候也被稱作
"GC堆"(Garbage Collected Heap)

3.方法區(qū):所有線程共享的內(nèi)存區(qū)域,它用于存儲已被虛擬
機加載的類信息功炮,常量,靜態(tài)變量术唬,即時編譯器編譯后
的代碼等數(shù)據(jù)

實驗結果

在單線程下薪伏,無論由于棧幀太大還是虛擬機棧容量太
小,當內(nèi)存無法分配時虛擬機拋出的都是
StackOverflowError異常

p.s


程序運行參數(shù)圖

程序運行結果圖

github鏈接(使用kotlin實現(xiàn))
https://github.com/joeytsai03/JVMStudy/blob/master/src/num2/code2_4.kt



2.多線程導致內(nèi)存溢出異常

測試思路

如果測試時不限單線程粗仓,通過不斷創(chuàng)建線程的方式倒是
可以產(chǎn)生內(nèi)存溢出異常嫁怀,這種情況下设捐,為每個線程的棧
分配的內(nèi)存越大,反而越容易產(chǎn)生內(nèi)存溢出異常

使用工具

JProfiler用于查看線程使用情況
Idea安裝JProfiler

code2_5虛擬機參數(shù)

參數(shù):     -Xss2M

code2_5代碼

package num2

/**
 * Created by Joey_Tsai on 2018/3/6.
 *VM: -Xss200M
 */
class JavaVMStackOOM{
    private fun dontStop() : Unit{
        while (true){

        }
    }
    public fun stackLeakByThread():Unit{
        while (true){
            val thread : Thread = Thread(Runnable(){
                @Override
                fun run(){
                    dontStop()
                }
            });
            thread.start()
        }
    }
}

fun main(args : Array<String>){
    val oom = JavaVMStackOOM()
    oom.stackLeakByThread()
}

操作系統(tǒng)內(nèi)存分配

譬如塘淑,在32位的windows系統(tǒng)中給每個線程分配的內(nèi)存
限制為2g挡育,虛擬機提供了參數(shù)來控制java堆和方法區(qū)這
兩部分內(nèi)存的最大值,剩余的內(nèi)存為2GB減去Xmx(最大
堆容量)朴爬,再減去MaxPermSize(最大方法區(qū)容量),程序
計數(shù)器消耗內(nèi)存很小橡淆,可以忽略召噩。

p.s


程序運行參數(shù)圖

github鏈接(使用kotlin實現(xiàn))
https://github.com/joeytsai03/JVMStudy/blob/master/src/num2/code2_5.kt



                          分    割    線


2_4_3 方法區(qū)和運行時常量池溢出

1.運行時常量池導致的內(nèi)存溢出異常

測試思路

運行時常量池是方法區(qū)的一部分,jdk7開始逐步去除永久
代,String.intern()是一個Native方法,在jdk1.6及之前的版
本中逸爵,由于常量池分配在永久代中具滴,我們可以通過
-XX:PermSize與 -XX:MaxPermSize限制方法區(qū)大小,從
而限制常量池容量大小

code2_6虛擬機參數(shù)

VM:-XX:PermSize=10M -XX:MaxPermSize=10M

code2_6代碼

package num2

/**
 * Created by Joey_Tsai on 2018/3/6.
 * VM:-XX:PermSize=10M -XX:MaxPermSize=10M
 */
class RuntimeConstantPoolOOM2_6{

}
fun main(args : Array<String>){
    //使用List保持著常量池引用师倔,避免Full GC回收常量池行為
    val list : MutableList<String>?=ArrayList<String>();
    //10MB的permSize在integer范圍內(nèi)足夠產(chǎn)生OOM了
    var i : Int = 0
    while (true){
        list?.add(i++.toString().intern())
        println(i)
    }
}

實驗結果

運行時常量池溢出,在"OutOfMemoryError"后面跟著的提示信息
是"PermGen space",說明運行時常量池屬于方法區(qū)(HotSpot虛擬機中的永
久代)的一部分构韵,在jdk1.7中則不會得到相同結果,while將一直循環(huán)下去趋艘。

2.String.intern返回引用測試

code2_7代碼

package num2

/**
 * Created by Joey_Tsai on 2018/3/6.
 */
public class RuntimeConstantPoolOOM2_7{
    
}

fun main(args: Array<String>) {
    val str1 : String = StringBuilder("計算機").append("軟件").toString()
    println(str1.intern() == str1)

    val str2 : String = StringBuilder("ja").append("va").toString()
    println(str2.intern() == str2)
}

JDK1.6中的intern() 與 JDK1.7中的intern()

在JDK1.6中,intern()會把首次遇到的字符串實例復制在永久代中疲恢,返回的
也是永久代中這個字符串實例的引用,而StringBuilder創(chuàng)建的字符串實例
在java堆上瓷胧,所以必然不是同一個引用显拳,將返回false。而JDK1.7中的
intern()實現(xiàn)不會再復制實例搓萧,只是在常量池中記錄首次出現(xiàn)的引用杂数,因此
intern()返回的引用和由StringBuilder創(chuàng)建的那個字符串實例是同一個。對
于str2返回false是因為'java'這個字符串在執(zhí)行StringBuilder.toString()之前
已經(jīng)出現(xiàn)過瘸洛,字符串常量池已經(jīng)有它的引用揍移,不符合首次出現(xiàn)原則,而'計
算機軟件'這個字符串則是首次出現(xiàn)返回true反肋。  
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末那伐,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子石蔗,更是在濱河造成了極大的恐慌喧锦,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,681評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抓督,死亡現(xiàn)場離奇詭異燃少,居然都是意外死亡,警方通過查閱死者的電腦和手機铃在,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評論 3 399
  • 文/潘曉璐 我一進店門阵具,熙熙樓的掌柜王于貴愁眉苦臉地迎上來碍遍,“玉大人,你說我怎么就攤上這事阳液∨戮矗” “怎么了?”我有些...
    開封第一講書人閱讀 169,421評論 0 362
  • 文/不壞的土叔 我叫張陵帘皿,是天一觀的道長东跪。 經(jīng)常有香客問我,道長鹰溜,這世上最難降的妖魔是什么虽填? 我笑而不...
    開封第一講書人閱讀 60,114評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮曹动,結果婚禮上斋日,老公的妹妹穿的比我還像新娘。我一直安慰自己墓陈,他們只是感情好恶守,可當我...
    茶點故事閱讀 69,116評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著贡必,像睡著了一般兔港。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上仔拟,一...
    開封第一講書人閱讀 52,713評論 1 312
  • 那天押框,我揣著相機與錄音,去河邊找鬼理逊。 笑死橡伞,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的晋被。 我是一名探鬼主播兑徘,決...
    沈念sama閱讀 41,170評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼羡洛!你這毒婦竟也來了挂脑?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 40,116評論 0 277
  • 序言:老撾萬榮一對情侶失蹤欲侮,失蹤者是張志新(化名)和其女友劉穎崭闲,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體威蕉,經(jīng)...
    沈念sama閱讀 46,651評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡刁俭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,714評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了韧涨。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片牍戚。...
    茶點故事閱讀 40,865評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡侮繁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出如孝,到底是詐尸還是另有隱情宪哩,我是刑警寧澤,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布第晰,位于F島的核電站锁孟,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏茁瘦。R本人自食惡果不足惜品抽,卻給世界環(huán)境...
    茶點故事閱讀 42,211評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望腹躁。 院中可真熱鬧,春花似錦南蓬、人聲如沸纺非。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,699評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽烧颖。三九已至,卻和暖如春窄陡,著一層夾襖步出監(jiān)牢的瞬間炕淮,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,814評論 1 274
  • 我被黑心中介騙來泰國打工跳夭, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留涂圆,地道東北人。 一個月前我還...
    沈念sama閱讀 49,299評論 3 379
  • 正文 我出身青樓币叹,卻偏偏與公主長得像润歉,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子颈抚,可洞房花燭夜當晚...
    茶點故事閱讀 45,870評論 2 361

推薦閱讀更多精彩內(nèi)容