java堆内存 数据结构_JAVA内存区域
首先解釋下內(nèi)存溢出和內(nèi)存泄露之間的區(qū)別,為后面的學(xué)習(xí)做些鋪墊:
1、內(nèi)存溢出和內(nèi)存泄露的區(qū)別和聯(lián)系
內(nèi)存溢出 out of memory:是指程序申請(qǐng)內(nèi)存時(shí),沒(méi)有足夠的內(nèi)存供申請(qǐng)者使用,或者說(shuō),給了你一塊存儲(chǔ)int類型數(shù)據(jù)的存儲(chǔ)空間,但是你卻存儲(chǔ)long類型的數(shù)據(jù),那么結(jié)果就是內(nèi)存不夠用,此時(shí)就會(huì)報(bào)錯(cuò)OOM,即所謂的內(nèi)存溢出
內(nèi)存泄露 memory leak:是指程序在申請(qǐng)內(nèi)存后,無(wú)法釋放已申請(qǐng)的內(nèi)存空間,一次內(nèi)存泄漏似乎不會(huì)有大的影響,但內(nèi)存泄漏堆積后的后果就是內(nèi)存溢出。
memory leak會(huì)最終會(huì)導(dǎo)致out of memory!
2、JVM中的堆棧和數(shù)據(jù)結(jié)構(gòu)中堆棧的區(qū)別
在數(shù)據(jù)結(jié)構(gòu)中,堆是完全二叉樹(shù),堆中個(gè)元素是有序的。而棧是一種特殊的線性表,具有先進(jìn)后出,只允許在一端(棧頂)插入、刪除的特點(diǎn)。
在jvm虛擬機(jī)中的堆棧對(duì)應(yīng)內(nèi)存的不同區(qū)域,籠統(tǒng)的說(shuō)堆是用于存放對(duì)象的內(nèi)存塊,棧是用于執(zhí)行程序的內(nèi)存塊。
下面切入正題
運(yùn)行時(shí)數(shù)據(jù)區(qū)域
Java虛擬機(jī)在執(zhí)行java程序的過(guò)程中會(huì)把它所管理的內(nèi)存劃分為若干個(gè)不同的數(shù)據(jù)區(qū)域,這些區(qū)域有各自的用途,以及創(chuàng)建和銷毀的時(shí)間。有的區(qū)域隨著虛擬機(jī)進(jìn)程的啟動(dòng)而存在,有些區(qū)域則依賴用戶線程的啟動(dòng)和結(jié)束而建立和銷毀。java虛擬機(jī)所管理的內(nèi)存將會(huì)包含以下幾個(gè)運(yùn)行時(shí)數(shù)據(jù)區(qū)域
1、線程獨(dú)有的內(nèi)存區(qū)域有如下幾塊:
(1)、程序計(jì)數(shù)器:是一塊較小的內(nèi)存空間,它可以看作是當(dāng)前線程所執(zhí)行字節(jié)碼的行號(hào)指示器。在虛擬機(jī)的概念模型里,字節(jié)碼解釋器工作時(shí)就是通過(guò)改變這個(gè)計(jì)數(shù)器的值來(lái)取下一條需要執(zhí)行的字節(jié)碼的指令。由于Java虛擬機(jī)的多線程是通過(guò)線程輪流切換并分配處理器執(zhí)行時(shí)間的方式實(shí)現(xiàn)的,在任何一個(gè)確定的時(shí)刻,一個(gè)處理器(對(duì)于多核處理器來(lái)說(shuō)就是一個(gè)核)都只會(huì)執(zhí)行一條線程中的指令。因此,為了線程切換后能恢復(fù)到正確的執(zhí)行位置,每條線程都需要有一個(gè)獨(dú)立的程序計(jì)數(shù)器,各條線程計(jì)數(shù)器互不影響,獨(dú)立存儲(chǔ),我們稱這類內(nèi)存為區(qū)域?yàn)椤熬€程私有”的內(nèi)存。
此內(nèi)存區(qū)域是唯一一個(gè)在java虛擬機(jī)規(guī)范中沒(méi)有規(guī)定任何OutOfMemoryError情況的區(qū)域。 (2)、java虛擬機(jī)棧:它的生命周期與線程相同。虛擬機(jī)棧描述的是java方法執(zhí)行的內(nèi)存模型,每個(gè)方法在執(zhí)行的同時(shí)都會(huì)創(chuàng)建一個(gè)棧幀用于存儲(chǔ)局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈接、方法出口等信息。每一個(gè)方法從調(diào)用直至執(zhí)行完成的過(guò)程,就對(duì)應(yīng)著棧幀在虛擬機(jī)中入棧到出棧的過(guò)程。
(3)、本地方法棧:與虛擬機(jī)棧發(fā)揮的作用是非常相似的,他們之間的區(qū)別不過(guò)是虛擬機(jī)棧為虛擬機(jī)執(zhí)行java方法(也就是字節(jié)碼)服務(wù),而本地方法棧則為虛擬機(jī)使用到的Native方法服務(wù)。
2、線程間共享的內(nèi)存區(qū)域有如下幾塊:
(1)、java堆:對(duì)于大多數(shù)java應(yīng)用來(lái)說(shuō),java堆是java虛擬機(jī)所管理的內(nèi)存中最大的一塊。Java堆是被所有線程共享的一塊內(nèi)存區(qū)域,在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建。此內(nèi)存區(qū)域的唯一目的就是存放對(duì)象實(shí)例,幾乎所有的對(duì)象實(shí)例都是在這里分配的。Java堆是垃圾收集器管理的主要區(qū)域,因此很多時(shí)候也被稱為“GC堆”(Garbage Collected Heap)。
(2)、方法區(qū):用于存儲(chǔ)已被虛擬機(jī)加載的類信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼數(shù)據(jù)。雖然java虛擬機(jī)規(guī)范把方法區(qū)描述為堆的一個(gè)邏輯部分,但它卻有一個(gè)別名叫做Non-Heap(非堆),目的是與java堆區(qū)分開(kāi)來(lái)。
(3)、運(yùn)行時(shí)常量池:是方法區(qū)的一部分。Class文件中除了有類的版本、字段、方法、接口、等描述信息外,還有一項(xiàng)信息是常量池,用于存放編譯期生成的各種字面量和符號(hào)引用,這部分內(nèi)容將在類加載后進(jìn)入方法區(qū)的運(yùn)行時(shí)常量池存放。既然運(yùn)行時(shí)常量池是方法區(qū)的一部分,再染收到方法區(qū)內(nèi)存的限制,當(dāng)常量池?zé)o法再申請(qǐng)到內(nèi)存時(shí)會(huì)拋出OutOfMemoryError異常。
3、直接內(nèi)存
直接內(nèi)存并不是虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)的一部分,也不是Java虛擬機(jī)規(guī)范中定義的內(nèi)存區(qū)域。但是這部分內(nèi)存也被頻繁地使用,而且也可能導(dǎo)致內(nèi)存溢出問(wèn)題。JDK1.4中新增加了NIO(參考https://www.ibm.com/developerworks/cn/education/java/j-nio/j-nio.html),引入了一種基于通道(channel)與緩沖區(qū)(buffer)的I/O方式,它可以使用Native函數(shù)庫(kù)直接分配堆外內(nèi)存,然后通過(guò)一個(gè)存儲(chǔ)在Java堆中的DirectByteBuffer對(duì)象作為這塊內(nèi)存的引用進(jìn)行操作。這樣能在一些場(chǎng)景中顯著提高性能,因?yàn)楸苊饬嗽贘ava堆和Native堆中來(lái)回復(fù)制數(shù)據(jù)。顯然,本機(jī)直接內(nèi)存的分配不會(huì)受到Java堆大小的限制,但是,既然是內(nèi)存,肯定還是會(huì)受到本機(jī)總內(nèi)存(包括RAM、SWAP區(qū))大小以及處理器尋址空間的限制。
分類: JAVA虛擬機(jī)
標(biāo)簽: JVM, JAVA, JAVA虛擬機(jī), OOM
總結(jié)
以上是生活随笔為你收集整理的java堆内存 数据结构_JAVA内存区域的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: win8登陆不用密码怎么设置 Win8设
- 下一篇: java jdbc rowset_JAV