常见OOM问题之PermGen space 永久空间问题详解

本文来自于HeapDump性能社区! !有性能问题,上HeapDump性能社区!

正文:

Java 应用程序只允许使用有限的内存量。您的特定应用程序可以使用的确切内存量是在应用程序启动期间指定的。为了让事情变得更复杂,Java 内存被分成不同的区域,如下图所示:

v2-acc3571aee7060370c492e0f8d4f69fa_1440w.png

所有这些区域的大小,包括 permgen 区域,都是在 JVM 启动期间设置的。如果您不自己设置大小,将使用特定于平台的默认值。

java.lang.OutOfMemoryError:PermGen space的消息表明永久代的内存区域被耗尽

1,什么原因造成的?

要了解java.lang.OutOfMemoryError: PermGen space 的原因,我们需要了解此特定内存区域的用途。

出于实际目的,永久代主要由加载并存储到 PermGen 中的类声明组成。这包括类的名称和字段、带有方法字节码的方法、常量池信息、与类关联的对象数组和类型数组以及即时编译器优化。

从上面的定义中,您可以推断出永久代的大小要求取决于加载的类的数量以及此类声明的大小。因此,我们可以说*java.lang.OutOfMemoryError: PermGen space 的*****主要原因是加载到永久代的类太多或类太大

2,举个例子

如上所述,永久代空间的使用与加载到 JVM 中的类数量密切相关。下面的代码是最直接

导入 javassist.ClassPool; 

public class MicroGenerator { 
  public static void main(String[] args) 抛出异常 { 
    for (int i = 0; i < 100_000_000; i++) { 
      generate("eu.plumbr.demo.Generated" + i); 
    } 
  } 

  public static Class generate(String name) throws Exception { 
    ClassPool pool = ClassPool.getDefault(); 
    返回 pool.makeClass(name).toClass(); 
  } 
}

在这个例子中,源代码遍历一个循环并在运行时生成类。javassist库负责处理类生成的复杂性。

启动上面的代码将继续生成新类并将它们的定义加载到永久空间中,直到空间被完全利用并抛出java.lang.OutOfMemoryError: Permgen 空间

重新部署时间示例

对于更复杂和更现实的示例,让我们带您了解在应用程序重新部署期间发生的java.lang.OutOfMemoryError: Permgen space错误。当您重新部署应用程序时,您会期望垃圾回收将摆脱引用所有先前加载的类的先前类加载器,并将其替换为加载类的新版本的类加载器。

不幸的是,许多 3rd 方库和对资源(例如线程、JDBC 驱动程序或文件系统句柄)的处理不当使得无法卸载以前使用的类加载器。这反过来意味着在每次重新部署期间,您的类的所有先前版本仍将驻留在 PermGen 中,在每次重新部署期间生成数十兆字节的垃圾

让我们想象一个使用 JDBC 驱动程序连接到关系数据库的示例应用程序。当应用程序启动时,初始化代码加载 JDBC 驱动程序以连接到数据库。对应于规范,JDBC 驱动程序使用java.sql.DriverManager注册自己。此注册包括在DriverManager的静态字段中存储对驱动程序实例的引用。

现在,当应用程序从应用程序服务器中卸载时,java.sql.DriverManager仍将保留该引用。我们最终获得了对驱动程序类的实时引用,该类又包含对用于加载应用程序的java.lang.Classloader实例的引用。这反过来意味着垃圾收集算法无法回收空间。

并且java.lang.ClassLoader 的那个实例仍然引用应用程序的所有类,通常在 PermGen 中占用数十兆字节。这意味着只需重新部署几次即可填充通常大小的 PermGen 并在日志中获取java.lang.OutOfMemoryError: PermGen space错误消息。

3,解决办法是什么?

1.解决初始化时OutOfMemoryError

当应用程序启动时触发由于 PermGen 耗尽导致的 OutOfMemoryError 时,解决方案很简单。应用程序只需要更多空间将所有类加载到 PermGen 区域,所以我们只需要增加它的大小。为此,请更改您的应用程序启动配置并添加(或增加(如果存在))类似于以下示例的-XX:MaxPermSize参数:

java -XX:MaxPermSize=512m com.yourcompany.YourClass

上述配置将告诉 JVM,允许 PermGen 增长到 512MB,然后才能开始以 OutOfMemoryError 的形式抱怨。

2.解决重新部署时OutOfMemoryError

当您重新部署应用程序后立即发生 OutOfMemoryError 时,您的应用程序会遭受类加载器泄漏。在这种情况下,解决问题的最简单,最直接的方式就是用工具排查,找到有问题的代码,并解决它以分钟为单位。

对于那些不能使用 Plumbr 或决定不使用的人,也可以使用替代方法。为此,您应该继续进行堆转储分析 - 在重新部署后使用类似于以下命令的命令进行堆转储:

jmap -dump:format=b,file=dump.hprof <process-id>

然后使用您最喜欢的堆转储分析器打开转储(Eclipse MAT 是一个很好的工具)。在分析器中,您可以查找重复的类,尤其是那些加载应用程序类的类。从那里,您需要进入所有类加载器以找到当前活动的类加载器。

对于不活动的类加载器,您需要通过从不活动的类加载器获取到GC 根的最短路径来确定阻止它们被垃圾收集的引用。有了这些信息,您就会找到根本原因。如果根本原因在 3rd 方库中,您可以继续访问 Google/StackOverflow 以查看这是否是获取补丁/解决方法的已知问题。如果这是您自己的代码,则需要删除违规引用。

3.解决运行时OutOfMemoryError

对于那些再次无法使用 Plumbr 的人,也可以使用另一种方法。在这种情况下,第一步是检查是否允许 GC 从 PermGen 卸载类。标准的 JVM 在这方面相当保守——类天生就是为了永生。所以一旦加载,即使没有代码再使用它们,类也会留在内存中。当应用程序动态创建大量类并且长时间不需要生成的类时,这可能会成为一个问题。在这种情况下,允许 JVM 卸载类定义会很有帮助。这可以通过向启动脚本添加一个配置参数来实现:

-XX:+CMSClassUnloadingEnabled

默认情况下,它设置为 false,因此要启用它,您需要在 Java 选项中显式设置以下选项。如果您启用CMSClassUnloadingEnabledGC 也会清除PermGen 并删除不再使用的类。请记住,此选项仅在使用以下选项启用UseConcMarkSweepGC时才有效。因此,当运行ParallelGC或,上帝保佑,Serial GC 时,请确保您已通过指定将 GC 设置为CMS

-XX:+UseConcMarkSweepGC

在确保可以卸载类并且问题仍然存在后,您应该继续进行堆转储分析 - 使用类似于以下的命令进行堆转储:

jmap -dump:file=dump.hprof,format=b <process-id>

然后使用您最喜欢的堆转储分析器(例如 Eclipse MAT)打开转储,并根据加载的类数量继续查找最昂贵的类加载器。从这样的类加载器中,您可以继续提取加载的类并按实例对此类类进行排序,以获得可疑的顶部列表。

对于每个嫌疑人,您需要手动将根本原因追溯到生成此类类的应用程序代码。

Java OOM系列专题:

第一篇:Java OOM 原理篇 : 什么是 Java OOM

第二篇:Java OOM 基础篇:常见的OutOfMemoryError 场景一:Java heap space 堆溢出问题详解

第三篇:Java OOM 基础篇:常见的OutOfMemoryError 场景二 : GC overhead limit exceeded 问题详解

第四篇:Java OOM 基础篇:常见的OutOfMemoryError 场景三: PermGen space 永久空间问题详解

第五篇:Java OOM 基础篇:常见的OutOfMemoryError 场景四: Permgen size 元空间问题详解

第六篇:Java OOM 实战篇:应用故障之Java heap space 堆溢出实战

第七篇:Java OOM 高级篇:体验了一把线上CPU100%及应用OOM的排查和解决过程

第八篇:Java OOM 高级篇:线上Docker 上Springboot程序OOM问题的排查分享

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,165评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,503评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,295评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,589评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,439评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,342评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,749评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,397评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,700评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,740评论 2 313
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,523评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,364评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,755评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,024评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,297评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,721评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,918评论 2 336

推荐阅读更多精彩内容