BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

Java 8会解决PermGen OutOfMemoryError问题吗?

| 作者 Fabian Lange 关注 0 他的粉丝 ,译者 臧秀涛 关注 2 他的粉丝 发布于 2013年3月12日. 估计阅读时间: 7 分钟 | Google、Facebook、Pinterest、阿里、腾讯 等顶尖技术团队的上百个可供参考的架构实例!

Java 8会解决PermGen OutOfMemoryError问题吗

Oracle正在合并HotSpot和JRockit的代码库,作为该项目的一部分,Oracle宣布他们会将PermGen从Java 8的HotSpot JVM中移除。然而很多人都认为这意味着所有的PermGen错误也将消失不见。因为现在可以通过Java 8 Early Access构建版本来检查移除PermGen的效果,所以是时候看看是不是所有PermGen问题都已解决了。

PermGen是什么?

Jon Masamitsu(JVM开发者,现就职于Oracle)曾于2006年在其博客上解释过永久代(Permanent Generation)的用途:永久代包含了类相关的信息,包括字节码、名字和JIT等信息。它被保存在一个独立的空间中,因为它通常是静态的,垃圾收集改为垃圾回收。

PermGen带来的问题

很多开发者都在其系统中见过“java.lang.OutOfMemoryError: PermGen space”这一问题。这往往是由类加载器相关的内存泄漏以及新类加载器的创建导致的,通常出现于代码热部署时。相对于正式产品,该问题在开发机上出现的频率更高,正是这个原因。当它在产品中出现时,开发者可以拿到生成的堆转储文件,并利用像Eclipse Memory Analyzer Toolkit这样的工具来寻找应该卸载却没被卸载的类加载器。除非通过特定配置阻止,PermGen也是会进行垃圾回收的。然而,在出现内存泄漏时,就没什么可回收的了。在产品中最常见的“问题”是64MB这个默认值太低了。常用的解决方法是将其设置为256MB。

Java 8改变了什么

Jon 在HotSpot开发邮件列表中解释了Java 8将发生的变化:Java 8中再也没有PermGen了。其中的某些部分,如被intern的字符串,在Java 7中已经移到了普通堆里。其余结构在Java 8中会被移到称作“Metaspace”的本机内存区中,该区域在默认情况下会自动生长,也会被垃圾回收。它有两个标记:MetaspaceSize和MaxMetaspaceSize。

应InfoQ的要求,Jon Masamitsu解释了其背后的设计目标:

移除了PermGen,用户就无需考虑如何正确设置其大小了,这是我们的一个目标。

如果知道应用程序的类数据需要更多空间,可以把MetaspaceSize设置的比默认值大些。 这能减少一些启动时的GC次数。不过没必要这么做。除非你想尽量减少GC次数,否则我不建议这么做。

如果想限制类数据所占空间的大小,可以设置MaxMetaspaceSize。如果怀疑出现类加载器泄漏,并且希望应用在耗尽太多本机内存前停止,应该设置它。还有一种使用场合,那就是在一个服务器上运行了多个应用,而且用户希望限制每个应用所占的类空间大小。

因此设置MetaspaceSize会潜在影响头几次垃圾回收,大部分情况下并不重要。这也反映出类似旧式PermSize标记的用途。

在设置了MaxMetaspaceSize的情况下,该空间的内存仍然会耗尽,进而引发“java.lang.OutOfMemoryError: Metadata space”错误。因为类加载器的泄漏仍然存在,而通常Java又不希望无限制地消耗本机内存,因此设置一个类似于MaxPermSize的限制看起来也是合理的。与PermGen类似,verbose: GC日志会打印Metaspace当前的内存消耗情况。使用命令行标记PermSize或MaxPermSize会导致一个警告,通知用户切换为Metaspace标记。

结论

因为Metaspace和PermGen的理念几乎是相同的,管理员在将Java 7升级到Java 8时,只需执行sed 'e/Perm/Metaspace/g'就能修改相应标记。

总的来说,变化看起来平淡无奇。大多数情况下,只是名字变了一下。默认情况下不限制Metaspace,以避免所选的默认值太小,但为了保证系统的稳定性又需要设置一下最大值。幸运的是我们可以复用PermSize和MaxPermSize的配置——几乎每个人都用过——只需要改一下标记即可。遗憾的是,从托管Java堆迁移到本机内存意味着堆转储文件中有价值的故障诊断信息少了许多,这正是Kirk Pepperdine所担忧的

最后,类加载器泄漏的问题和以前一样,仍然会出现。

译者补记

英文站原新闻下有些评论,读者Ronald Miura并不同意本文的结论,他不客气地评论道:

如果将类信息加载到有限内存区域中,最后会出现OutOfMemoryError。如果不使用有限的区域,你会得到“不稳定的系统”。

还“平淡无奇”,你想要什么,让JVM自动修正你的内存泄漏bug吗?

来自Oracle的Cameron Purdy倒是很平和:

还是会好一些的。之前不管是不是需要,JVM都会吃掉那块空间……如果设置得太小,JVM会死掉;如果设置得太大,这块内存就被JVM浪费了。理论上说,现在你完全可以不关注这个,因为JVM会在运行时自动调校为“合适的大小”。

peter lin对Ronald Miura的意见表示赞同,他补充说:

过去我使用并测试过JRockit,由JVM来管理PermGen,开发者就轻松多了。我都记不清tomcat用户在邮件列表中问过我多少次相关的问题了。

Ronald Miura后来又补充了一下自己的意见:

……我认为这种改变是巨大的进步。

我很反感本文的结论,把这种改动诋毁为“平淡无奇”。如果你期望的是无解问题(自动修复你的bug)的神奇方案,那才算“平淡无奇”吧。

亲爱的InfoQ读者,你怎样看待这个问题?欢迎参与讨论。

查看英文原文Will Java 8 solve PermGen OutOfMemoryError?

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

Confusing by SU苏 信东

对于Java开发者来说,最难掌握的就是为何一个会自动进行垃圾收集的环境还会出现Memory leak以及Out of memory问题。

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

1 讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT