Java内存体系结构(模型),垃圾回收和内存泄漏
Java內(nèi)存架構(gòu)(Java內(nèi)存模型)
上面是堆的Java內(nèi)存模型以及Java虛擬機(jī)(JVM)中運(yùn)行的任何Java應(yīng)用程序的PermGen。 還提供了比率,以使您更好地了解如何在每種世代類型之間分配允許的內(nèi)存。 以上所有內(nèi)容完全適用于Java 1.7版(含)。 上面也稱為內(nèi)存模型的“管理區(qū)域”。
除上述內(nèi)容外,還有一個(gè)堆棧區(qū)域,可以使用-Xss選項(xiàng)進(jìn)行配置。 該區(qū)域保存堆上的引用,本機(jī)引用,pc寄存器,代碼緩存和所有線程的局部變量。 這也稱為內(nèi)存模型的“本地區(qū)域”。
Java內(nèi)存模型的受管區(qū)域(Java內(nèi)存體系結(jié)構(gòu))
[年輕一代/苗圃]伊甸園空間
所有新對(duì)象都首先在Eden Space中創(chuàng)建。 一旦達(dá)到由JVM確定的任意閾值,就會(huì)啟動(dòng)次要垃圾回收(Minor GC)。它首先刪除所有非引用對(duì)象,并將引用對(duì)象從“ eden”和“ from”移到“ to”幸存者空間。 GC結(jié)束后,將交換“從”和“到”角色(名稱)。
[年輕一代/苗圃]幸存者1(來(lái)自)
這是幸存者空間的一部分(您可能認(rèn)為這是幸存者空間中的角色 )。 這是上一個(gè)垃圾回收(GC)期間的“ to”角色。
[年輕一代/苗圃] Suvrivor 2(至)
這也是幸存者空間的一部分(您可能認(rèn)為這也是幸存者空間中的角色 )。 在這里,在GC期間,所有引用的對(duì)象
從'from'和'eden'移到。
[上一代]終身任職
根據(jù)閾值限制,可以使用-XX:+ PrintTenuringDistribution來(lái)檢查閾值限制,該限制按年齡顯示對(duì)象(以字節(jié)為單位的空間)–對(duì)象從“到” 幸存者空間移動(dòng)到Tenured空間。 “年齡”是指它在幸存者空間內(nèi)移動(dòng)的次數(shù)。 還有其他重要的標(biāo)志,例如-XX:InitialTenuringThreshold,-XX:MaxTenuringThreshold和-XX:TargetSurvivorRatio ,它們可以優(yōu)化使用權(quán)和幸存者空間。 通過(guò)設(shè)置-XX:InitialTenuringThreshold和-XX:MaxTenuringThreshold,我們?cè)试S'Age'的初始值和最大值,同時(shí)保持-XX:+ NeverTenure和-XX指定的'Survivor(To)'中的百分比利用率。 + AlwaysTenure,正如他們建議的那樣,要么永不保管對(duì)象(使用風(fēng)險(xiǎn)較大 ),相反的用法是始終保有權(quán),即始終使用“老一代”。 這里發(fā)生的垃圾收集是主要垃圾收集(主要GC)。 通常在堆已滿或舊代已滿時(shí)觸發(fā)。 這通常是接管執(zhí)行垃圾回收的“ 世界停止 ”事件或線程。 還有另一種稱為完全垃圾收集(Full GC)的GC,它涉及其他內(nèi)存區(qū)域,例如permgen空間。
與整個(gè)堆相關(guān)的其他重要且有趣的標(biāo)志是-XX:SurvivorRatio和-XX:NewRatio ,它們指定eden空間與幸存者空間的比率以及舊一代與新一代的比率。
[永久世代] Permgen空間
“ Permgen”用于存儲(chǔ)以下信息:常量池(內(nèi)存池),字段和方法數(shù)據(jù)以及代碼。 它們每個(gè)都與名稱所暗示的特征相同。
垃圾收集算法
串行GC(-XX:UseSerialGC):年輕一代和老一代的GC
為年輕和終身使用的一代使用簡(jiǎn)單的標(biāo)記掃描緊湊循環(huán)。 這對(duì)于客戶端系統(tǒng)以及內(nèi)存占用量少和cpu較小的系統(tǒng)來(lái)說(shuō)非常有用
并行GC(-XX:UseParallelGC):年輕一代和老一代的GC
這使用了N個(gè)線程,可以使用-XX:ParallelGCThreads = N進(jìn)行配置,這里N也是CPU內(nèi)核的數(shù)量。 用于垃圾收集。 它在Young代中將這N個(gè)線程用于GC,而在Old代中僅使用一個(gè)線程。
并行舊GC(-XX:UseParallelOldGC):年輕一代和老一代的GC
這與Parallel GC相同,不同之處在于它在舊一代和年輕一代中均使用N個(gè)線程進(jìn)行GC。
并發(fā)標(biāo)記和掃描GC(-XX:ConcMarkSweepGC):舊Generaton上的GC
顧名思義,CMS GC將GC所需的停頓最小化。 創(chuàng)建高響應(yīng)性的應(yīng)用程序最有用,并且僅在舊一代中才執(zhí)行GC。 它為GC創(chuàng)建了多個(gè)線程,這些線程與應(yīng)用程序線程并發(fā)工作,可以使用-XX:ParallelCMSThreads = n指定這些線程。
G1 GC(-XX:UseG1GC):年輕一代和老年人一代的GC(通過(guò)將堆分成相等大小的區(qū)域)
這是一個(gè)并行,并發(fā)且遞增壓縮的低暫停垃圾收集器。 它是在Java 7中引入的,其最終目標(biāo)是取代CMS GC。 它將堆劃分為多個(gè)大小相等的區(qū)域,然后執(zhí)行GC,通常從實(shí)時(shí)數(shù)據(jù)較少的區(qū)域開(kāi)始-因此,即“垃圾優(yōu)先”。
最常見(jiàn)的內(nèi)存不足問(wèn)題
所有Java開(kāi)發(fā)人員都應(yīng)該知道的最常見(jiàn)的內(nèi)存不足問(wèn)題,以便正確地開(kāi)始調(diào)試,如下所示:
- 線程“ main”中的異常:java.lang.OutOfMemoryError:Java堆空間這并不一定意味著內(nèi)存泄漏,這可能是由于為堆配置的空間較小所致。 否則,在壽命長(zhǎng)的應(yīng)用程序中,可能是由于無(wú)意中提到了對(duì)堆對(duì)象的引用(內(nèi)存泄漏)。 甚至應(yīng)用程序調(diào)用的API都可能包含對(duì)不必要的對(duì)象的引用。 同樣,在過(guò)度使用終結(jié)器的應(yīng)用程序中,有時(shí)對(duì)象會(huì)排隊(duì)到終結(jié)隊(duì)列中。 當(dāng)這樣的應(yīng)用程序創(chuàng)建更高優(yōu)先級(jí)的線程并導(dǎo)致finalizaton隊(duì)列中的對(duì)象越來(lái)越多時(shí),它可能導(dǎo)致內(nèi)存不足。
- 線程“ main”中的異常:java.lang.OutOfMemoryError:PermGen空間如果加載了許多類和方法,或者創(chuàng)建了很多字符串文字,尤其是通過(guò)使用intern()(從JDK 7開(kāi)始,不再使用實(shí)習(xí)字符串) (PermGen的一部分)–則發(fā)生這種類型的錯(cuò)誤。 發(fā)生此類錯(cuò)誤時(shí),文本ClassLoader.defineClass可能會(huì)出現(xiàn)在所打印的堆棧跟蹤頂部附近。
- 線程“ main”中的異常:java.lang.OutOfMemoryError:請(qǐng)求的數(shù)組大小超出VM限制當(dāng)請(qǐng)求的數(shù)組大小大于可用堆大小時(shí),再次發(fā)生這種情況。 如果為數(shù)組大小請(qǐng)求一個(gè)非常大的值,通常可能由于運(yùn)行時(shí)的程序錯(cuò)誤而發(fā)生。
- 線程“ main”中的異常:java.lang.OutOfMemoryError:請(qǐng)求<r>的<s>個(gè)字節(jié)。 交換空間不足?
通常這可能是內(nèi)存泄漏的根本原因。 當(dāng)操作系統(tǒng)沒(méi)有足夠的交換空間或另一個(gè)進(jìn)程占用系統(tǒng)上所有可用的內(nèi)存資源時(shí),就會(huì)發(fā)生這種情況。 簡(jiǎn)而言之,由于空間耗盡,它無(wú)法從堆中提供請(qǐng)求空間。 該消息指示失敗的請(qǐng)求的大小“ s”(以字節(jié)為單位)以及內(nèi)存請(qǐng)求的原因“ r”。 在大多數(shù)情況下,消息的<r>部分是報(bào)告分配失敗的源模塊的名稱,盡管在某些情況下它表示原因。 - 線程“ main”中的異常:java.lang.OutOfMemoryError:<原因> <堆棧跟蹤>(本機(jī)方法)
這表明本機(jī)方法遇到分配失敗。 根本原因是該錯(cuò)誤發(fā)生在JNI中,而不是在JVM內(nèi)部執(zhí)行的代碼中發(fā)生。 當(dāng)本機(jī)代碼不檢查內(nèi)存分配錯(cuò)誤時(shí),應(yīng)用程序?qū)⒈罎⒍皇呛谋M內(nèi)存。
內(nèi)存泄漏的定義
“將內(nèi)存泄漏視為一種疾病,而將OutOfMemoryError視為一種癥狀。 但是,并非所有OutOfMemoryErrors都暗示內(nèi)存泄漏,并且并非所有內(nèi)存泄漏都將自身表現(xiàn)為OutOfMemoryErrors。 ”
在《計(jì)算機(jī)科學(xué)》中,內(nèi)存泄漏是一種資源泄漏,當(dāng)計(jì)算機(jī)程序錯(cuò)誤地管理內(nèi)存分配以致不再釋放不再需要的內(nèi)存時(shí),就會(huì)發(fā)生這種情況。 在面向?qū)ο蟮木幊讨?,當(dāng)對(duì)象存儲(chǔ)在內(nèi)存中但無(wú)法被運(yùn)行的代碼訪問(wèn)時(shí),可能會(huì)發(fā)生內(nèi)存泄漏。
Java中內(nèi)存泄漏的常見(jiàn)定義:
當(dāng)不必要的對(duì)象引用被不必要地維護(hù)時(shí),就會(huì)發(fā)生內(nèi)存泄漏。
在Java中,內(nèi)存泄漏是指某些對(duì)象不再被應(yīng)用程序使用,但是GC無(wú)法將其識(shí)別為未使用的情況。
當(dāng)程序中不再使用某個(gè)對(duì)象,但仍在無(wú)法訪問(wèn)的某個(gè)位置引用該對(duì)象時(shí),將出現(xiàn)內(nèi)存泄漏。 因此,垃圾收集器無(wú)法刪除它。 用于此對(duì)象的內(nèi)存空間不會(huì)釋放,并且用于程序的總內(nèi)存將增加。 隨著時(shí)間的推移,這將降低性能,并且JVM可能會(huì)耗盡內(nèi)存。
從某種意義上說(shuō),當(dāng)在永久性空間上無(wú)法分配任何內(nèi)存時(shí),就會(huì)發(fā)生內(nèi)存泄漏。
內(nèi)存泄漏的一些最常見(jiàn)原因是:
我建議使用與JDK捆綁在一起的Visual VM,以開(kāi)始調(diào)試內(nèi)存泄漏問(wèn)題。
內(nèi)存泄漏的常見(jiàn)調(diào)試
調(diào)試內(nèi)存泄漏問(wèn)題的常用策略或步驟包括:
- 識(shí)別癥狀
- 啟用詳細(xì)垃圾回收
- 啟用分析
- 分析痕跡
祝幸福時(shí)光,解決Java內(nèi)存問(wèn)題!
翻譯自: https://www.javacodegeeks.com/2015/11/java-memory-architecture-model-garbage-collection-and-memory-leaks.html
總結(jié)
以上是生活随笔為你收集整理的Java内存体系结构(模型),垃圾回收和内存泄漏的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: jnby是什么牌子 jnby是哪个牌子
- 下一篇: JavaOne演讲者选择了您不应该错过的