程序小白在寫(xiě)代碼的過(guò)程中,經(jīng)常會(huì)不經(jīng)意間寫(xiě)出發(fā)生內(nèi)存溢出異常的代碼。很多時(shí)候這類(lèi)異常如何產(chǎn)生的都傻傻弄不清楚,如果能故意寫(xiě)出讓jvm發(fā)生內(nèi)存溢出的代碼,有時(shí)候看來(lái)也并非一件容易的事。最近通過(guò)學(xué)習(xí)《深入理解java虛擬機(jī)-JVM高級(jí)特性與最佳實(shí)踐》這本書(shū),終于初步了解了一下java虛擬機(jī)的內(nèi)存模型。本文通過(guò)寫(xiě)出使jvm發(fā)生內(nèi)存溢出異常的代碼來(lái)對(duì)自己的學(xué)習(xí)結(jié)果進(jìn)行總結(jié),同時(shí)也提醒自己以后寫(xiě)代碼時(shí)候不要再跳進(jìn)這個(gè)坑啦。
java的內(nèi)存管理是由java虛擬機(jī)自動(dòng)進(jìn)行管理的,并不需要程序員過(guò)多的手動(dòng)干預(yù),這也就導(dǎo)致了初學(xué)java的人在不了解java內(nèi)存模型的情況下也能愉快的進(jìn)行coding。不過(guò)一旦涉及了內(nèi)存泄露或者內(nèi)存溢出以及垃圾回收(GC)方面的問(wèn)題,如果不了解虛擬機(jī)是怎么管理內(nèi)存的,那么排查問(wèn)題,定位錯(cuò)誤地點(diǎn)就顯得無(wú)從下手了。首先上圖看一下java虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)是什么樣子(圖片來(lái)源于網(wǎng)絡(luò)):
從上圖我們可以獲得以下信息:
jvm內(nèi)存分區(qū)可以分為所有線程共享數(shù)據(jù)區(qū)以及線程隔離數(shù)據(jù)區(qū)兩部分。這也就是說(shuō)圖中的方法區(qū)和堆是由所有的線程共同使用的,而虛擬機(jī)棧、本地方法棧、程序計(jì)數(shù)器則是每個(gè)線程獨(dú)有各自的響應(yīng)數(shù)據(jù)區(qū),各線程之間是互不干擾的。
jvm運(yùn)行時(shí)數(shù)據(jù)區(qū)按照功能可分為方法區(qū),堆,虛擬機(jī)棧,本地方法棧,程序計(jì)數(shù)器五個(gè)部分。各個(gè)部分存儲(chǔ)的數(shù)據(jù)類(lèi)型不同。
本文主要講述如何讓JVM發(fā)生內(nèi)存溢出異常,有關(guān)JVM內(nèi)存模型將會(huì)在另一篇文章中詳細(xì)講解,這里簡(jiǎn)單介紹各分區(qū)的作用:
堆:各線程共享;存放java對(duì)象實(shí)例,以及為數(shù)組分配的空間也在此處
虛擬機(jī)棧:線程私有;生命周期與線程相同,描述java方法執(zhí)行的內(nèi)存模型,每個(gè)方法在執(zhí)行時(shí)創(chuàng)建棧幀,棧幀存儲(chǔ)局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈接、返回地址(方法出口)等信息
本地方法棧:和虛擬機(jī)棧功能類(lèi)似,線程私有;為虛擬機(jī)使用的Native方法提供服務(wù)
方法區(qū):各線程共享;存儲(chǔ)已被虛擬機(jī)加載的類(lèi)的信息、final聲明的常量,static修飾的靜態(tài)變量,以及編譯器編譯后的java代碼等數(shù)據(jù)(jdk7以后把常量池移到了堆中)
程序計(jì)數(shù)器:線程私有;可以看做是當(dāng)前線程所執(zhí)行程序的字節(jié)碼的行號(hào)指示器
在jvm規(guī)范中,除了程序計(jì)數(shù)器內(nèi)存區(qū)域沒(méi)有規(guī)定任何內(nèi)存溢出異常情形外,其他四個(gè)內(nèi)存區(qū)域都會(huì)有相應(yīng)的內(nèi)存溢出異常發(fā)生的可能,所以jvm內(nèi)存溢出異常發(fā)生在不同的內(nèi)存區(qū)域具有不同的異常發(fā)生原因,知道一內(nèi)存異常產(chǎn)生的位置,對(duì)于定位錯(cuò)誤地點(diǎn)就很有指向性了。
下面就通過(guò)實(shí)例來(lái)展示,如何通過(guò)代碼指定讓不同的內(nèi)存區(qū)域發(fā)生內(nèi)存溢出異常。
一、java堆發(fā)生內(nèi)存溢出:
java堆是用來(lái)存儲(chǔ)對(duì)象實(shí)例以及數(shù)組的,使java堆發(fā)生內(nèi)存溢出的要旨是:
不斷創(chuàng)建對(duì)象
保證對(duì)象存活,不會(huì)被垃圾收集器回收
java虛擬機(jī)的內(nèi)存大小是可以人為設(shè)置的,通過(guò)設(shè)置限制內(nèi)存大小,可以很方便的實(shí)現(xiàn)內(nèi)存溢出,節(jié)約了時(shí)間。
設(shè)置java堆內(nèi)存大小的虛擬機(jī)參數(shù)為:-Xms堆的初始大小 -Xmx堆可擴(kuò)展的最大值
延伸閱讀
學(xué)習(xí)是年輕人改變自己的最好方式