資源描述:
《Java中的OutOfMemoryError和JVM內(nèi)存結構》由會員上傳分享,免費在線閱讀,更多相關內(nèi)容在行業(yè)資料-天天文庫。
1、轉自liuchangit.comOutOfMemoryError在開發(fā)過程中是司空見慣的,遇到這個錯誤,新手程序員都知道從兩個方面入手來解決:一是排查程序是否有BUG導致內(nèi)存泄漏;二是調(diào)整JVM啟動參數(shù)增大內(nèi)存。OutOfMemoryError有好幾種情況,每次遇到這個錯誤時,觀察OutOfMemoryError后面的提示信息,就可以發(fā)現(xiàn)不同之處,如:java.lang.OutOfMemoryError:Javaheapspacejava.lang.OutOfMemoryError:unabletocreatenewnativethreadjav
2、a.lang.OutOfMemoryError:PermGenspacejava.lang.OutOfMemoryError:RequestedarraysizeexceedsVMlimit雖然都叫OutOfMemoryError,但每種錯誤背后的成因是不一樣的,解決方法也要視情況而定,不能一概而論。只有深入了解JVM的內(nèi)存結構并仔細分析錯誤信息,才有可能做到對癥下藥,手到病除。?JVM規(guī)范JVM規(guī)范對Java運行時的內(nèi)存劃定了幾塊區(qū)域(詳見這里),有:JVM棧(JavaVirtualMachineStacks)、堆(Heap)、方法區(qū)(Meth
3、odArea)、常量池(RuntimeConstantPool)、本地方法棧(NativeMethodStacks),但對各塊區(qū)域的內(nèi)存布局和地址空間卻沒有明確規(guī)定,而留給各JVM廠商發(fā)揮的空間。?HotSpotJVMSun自家的HotSpotJVM實現(xiàn)對堆內(nèi)存結構有相對明確的說明。按照HotSpotJVM的實現(xiàn),堆內(nèi)存分為3個代:YoungGeneration、Old(Tenured)Generation、PermanentGeneration。眾所周知,GC(垃圾收集)就是發(fā)生在堆內(nèi)存這三個代上面的。Young用于分配新的Java對象,其又被
4、分為三個部分:EdenSpace和兩塊SurvivorSpace(稱為From和To),Old用于存放在GC過程中從YoungGen中存活下來的對象,Permanent用于存放JVM加載的class等元數(shù)據(jù)。詳情參見HotSpot內(nèi)存管理白皮書。堆的布局圖示如下:?根據(jù)這些信息,我們可以推導出JVM規(guī)范的內(nèi)存分區(qū)和HotSpot實現(xiàn)中內(nèi)存區(qū)域的對應關系:JVM規(guī)范的Heap對應到Young和OldGeneration,方法區(qū)和常量池對應到PermanentGeneration。對于Stack內(nèi)存,HotSpot實現(xiàn)也沒有詳細說明,但HotSpot
5、白皮書上提到,Java線程棧是用宿主操作系統(tǒng)的棧和線程模型來表示的,Java方法和native方法共享相同的棧。因此,可以認為在HotSpot中,JVM棧和本地方法棧是一回事。?操作系統(tǒng)由于一個JVM進程首先是一個操作系統(tǒng)進程,因此會遵循操作系統(tǒng)進程地址空間的規(guī)定。32位系統(tǒng)的地址空間為4G,即最多表示4GB的虛擬內(nèi)存。在Linux系統(tǒng)中,高地址的1G空間(即0xC0000000~0xFFFFFFFF)被系統(tǒng)內(nèi)核占用,低地址的3G空間(即0×00000000~0xBFFFFFFF)為用戶程序所使用(顯然JVM進程運行在這3G的地址空間中)。這3G
6、的地址空間從低到高又分為多個段;Text段用于存放程序二進制代碼;Data段用于存放編譯時已初始化的靜態(tài)變量;BSS段用于存放未初始化的靜態(tài)變量;Heap即堆,用于動態(tài)內(nèi)存分配的數(shù)據(jù)結構,C語言的malloc函數(shù)申請的內(nèi)存即是從此處分配的,Java的new實例化的對象也是自此分配。不同于前面三個段,Heap空間是可變的,其上界由低地址向高地址增長。內(nèi)存映射區(qū),加載的動態(tài)鏈接庫位于這個區(qū)中;Stack即??臻g,線程的執(zhí)行即是占用棧內(nèi)存,??臻g也是可變的,但它是通過下界從高地址向低地址移動而增長的。詳情參見這里。圖示如下:?JVM本身是由native
7、code所編寫的,所以JVM進程同樣具有Text/Data/BSS/Heap/MemoryMapping/Stack等內(nèi)存段。而Java語言的Heap應當是建立在操作系統(tǒng)進程的Heap之上的,Java語言的Stack應該也是建立操作系統(tǒng)進程Stack之上的。綜合HotSpot的內(nèi)存區(qū)域和操作系統(tǒng)進程的地址空間,可以大致得到下列圖示:Java線程的內(nèi)存是位于JVM或操作系統(tǒng)的棧(Stack)空間中,不同于對象——是位于堆(Heap)中。這是很多新手程序員容易誤解的地方。注意,“Java線程的內(nèi)存”這個用詞不是指Java.lang.Thread對象的
8、內(nèi)存,java.lang.Thread對象本身是在Heap中分配的,當調(diào)用start()方法之后,JVM會創(chuàng)建一個執(zhí)行單元,最終會創(chuàng)建一