本文來自于HeapDump性能社區(qū)! !有性能問題,上HeapDump性能社區(qū)!
正文:
Java 應(yīng)用程序只能使用有限的內(nèi)存量。您的特定應(yīng)用程序可以使用的確切內(nèi)存量是在應(yīng)用程序啟動期間指定的。為了讓事情變得更復(fù)雜,Java 內(nèi)存被分成不同的區(qū)域,如下圖所示:

所有這些區(qū)域的大小,包括元空間區(qū)域,都可以在 JVM 啟動期間指定。如果您不自己確定大小,將使用特定于平臺的默認(rèn)值。
所述java.lang.OutOfMemoryError:元空間中消息指示所述元空間區(qū)域在存儲器中被耗盡。
1,是什么原因造成的?
如果您不是 Java 領(lǐng)域的新手,您可能熟悉 Java 內(nèi)存管理中的另一個概念,稱為 PermGen。從 Java 8 開始,Java 中的內(nèi)存模型發(fā)生了重大變化。引入了一個名為 Metaspace 的新內(nèi)存區(qū)域,并刪除了 Permgen。做出此更改的原因有多種,包括但不限于:
- permgen 所需的大小很難預(yù)測。它導(dǎo)致供應(yīng)不足觸發(fā)java.lang.OutOfMemoryError: Permgen size錯誤或過度供應(yīng)導(dǎo)致資源浪費。
- GC 性能改進(jìn),啟用并發(fā)類數(shù)據(jù)取消分配,無需GC 暫停和元數(shù)據(jù)上的特定迭代器
- 支持進(jìn)一步優(yōu)化,例如G1并發(fā)類卸載。
因此,如果您熟悉 PermGen,那么您需要了解的背景知識就是 – Java 8 之前 PermGen 中的任何內(nèi)容(類的名稱和字段、類的方法以及方法的字節(jié)碼、常量池、JIT 優(yōu)化等) ) – 現(xiàn)在位于元空間。
如您所見,元空間大小要求取決于加載的類的數(shù)量以及此類聲明的大小。所以很容易看到的主要原因java.lang.OutOfMemoryError:元空間是:太多的級別或過大的類加載到元空間。**
2,舉個例子
正如我們在前一章中解釋的那樣,元空間的使用與加載到 JVM 中的類的數(shù)量密切相關(guān)。下面的代碼是最直接的例子:
public class Metaspace {
static javassist.ClassPool cp = javassist.ClassPool.getDefault();
public static void main(String[] args) throws Exception{
for (int i = 0; ; i++) {
Class c = cp.makeClass("eu.plumbr.demo.Generated" + i).toClass();
}
}
}
在這個例子中,源代碼遍歷一個循環(huán)并在運行時生成類。所有這些生成的類定義最終都會消耗 Metaspace。類生成的復(fù)雜性由javassist庫處理。
代碼將不斷生成新類并將它們的定義加載到 Metaspace,直到空間被完全利用并且java.lang.OutOfMemoryError: Metaspace被拋出。當(dāng)使用-XX:MaxMetaspaceSize=64m啟動時,在 Mac OS X 上,我的 Java 1.8.0_05 在加載了大約 70,000 個類時死亡。
3,解決辦法是什么?
面對由于 Metaspace 導(dǎo)致的 OutOfMemoryError 時,第一個解決方案應(yīng)該是顯而易見的。如果應(yīng)用程序耗盡了內(nèi)存中的 Metaspace 區(qū)域,您應(yīng)該增加 Metaspace 的大小。更改您的應(yīng)用程序啟動配置并增加以下內(nèi)容:
-XX:MaxMetaspaceSize=512m
上面的配置示例告訴 JVM,允許 Metaspace 增長到 512 MB,然后才能開始以OutOfMemoryError的形式抱怨。
乍一看,另一種解決方案甚至更簡單。您可以通過刪除此參數(shù)來完全取消對元空間大小的限制。但請注意,這樣做可能會引入大量交換和/或?qū)е卤緳C(jī)分配失敗。
不過,在結(jié)束之前,請注意 - 通常情況下,通過使用上述推薦的“快速修復(fù)”,您最終會通過隱藏java.lang.OutOfMemoryError: Metaspace而沒有解決潛在問題來掩蓋癥狀。如果您的應(yīng)用程序泄漏內(nèi)存或只是將一些不合理的內(nèi)容加載到 Metaspace 中,上述解決方案實際上不會改善任何事情,只會推遲問題。
Java OOM系列專題:
第一篇:Java OOM 原理篇 : 什么是 Java OOM
第二篇:Java OOM 基礎(chǔ)篇:常見的OutOfMemoryError 場景一:Java heap space 堆溢出問題詳解
第三篇:Java OOM 基礎(chǔ)篇:常見的OutOfMemoryError 場景二 : GC overhead limit exceeded 問題詳解
第四篇:Java OOM 基礎(chǔ)篇:常見的OutOfMemoryError 場景三: PermGen space 永久空間問題詳解
第五篇:Java OOM 基礎(chǔ)篇:常見的OutOfMemoryError 場景四: Permgen size 元空間問題詳解
第六篇:Java OOM 實戰(zhàn)篇:應(yīng)用故障之Java heap space 堆溢出實戰(zhàn)