在工作中,我们经常遇到这样的问题:永久代内存不足 http://www.jroller.com/agileanswers/entry/preventing_java_s_java_lang例外,团队负责人认为这是 JVM 中的一个错误,与代码的热部署有关。他在没有解释很多细节的情况下指出,热部署是一个“难题”,困难到连 .NET 都无法解决还没做呢。
我发现很多文章从鸟瞰角度解释热部署,但总是缺乏技术细节。谁能给我指出一个技术解释,并解释为什么热部署是“一个难题”?
当加载一个类时,有关该类的各种静态数据都存储在 PermGen 中。只要存在对此 Class 实例的实时引用,该类实例就无法被垃圾回收。
我相信部分问题与 GC 是否应该从永久代中删除旧的类实例有关。通常,每次热部署时,新的类实例都会添加到 PermGen 内存池中,而现在未使用的旧实例通常不会被删除。默认情况下,Sun JVM 不会在 PermGen 中运行垃圾收集,但这可以通过可选的“java”命令参数来启用。
因此,如果热部署次数足够多,最终将耗尽 PermGen 空间。
如果您的网络应用程序没有关闭完全地当取消部署时(例如,如果它使线程保持运行),则该 Web 应用程序使用的所有类实例都将固定在 PermGen 空间中。您重新部署,现在所有这些类实例的另一个完整副本已加载到 PermGen 中。您取消部署,线程继续运行,将另一组类实例固定在 PermGen 中。您重新部署并加载一整套网络副本......最终您的 PermGen 被填满。
有时您可以通过以下方式解决此问题:
- 向最新的 Sun JVM 提供命令参数,以在 PermGen 和类中启用 GC。那是:
-XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled
- 使用不同的 JVM,不使用固定大小的 PermGen 或对加载的类执行 GC
但这会有所帮助only如果您的 Web 应用程序完全干净地关闭,则不会留下对该 Web 应用程序的类加载器加载的任何类的任何类实例的实时引用。
由于类加载器泄漏,即使这样也不一定能解决问题。 (在某些情况下,以及太多的内置字符串。)
查看以下链接了解更多信息(两个粗体链接有很好的图表来说明部分问题)。
- 类加载器泄漏:可怕的“java.lang.OutOfMemoryError:PermGen space”异常 http://frankkieviet.blogspot.com/2006/10/classloader-leaks-dreaded-permgen-space.html
- 未知的一代:烫发 http://dev.eclipse.org/blogs/memoryanalyzer/2008/05/17/the-unknown-generation-perm/
- 展示永久一代 http://blogs.oracle.com/jonthecollector/entry/presenting_the_permanent_generation
- Tomcat Wiki:如何处理内存不足错误 http://wiki.apache.org/tomcat/OutOfMemory
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)