Dealing with “java.lang.OutOfMemoryError: PermGen space” Error – 处理 “java.lang.OutOfMemoryError:PermGen space” 错误

最后修改: 2022年 10月 8日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

PermGen (Permanent Generation) is a peculiar piece of memory allocated for running JVM-based applications. PermGen error is one from the java.lang.OutOfMemoryError family, and it’s an indication of a resource (memory) exhaustion.

PermGen(永久生成)是为运行基于JVM的应用程序分配的一块奇特的内存。PermGen错误java.lang.OutOfMemoryError家族中的一种,它是资源(内存)耗尽的一种表现。

In this quick tutorial, we’ll look at what causes the java.lang.OutOfMemoryError: Permgen space error and how it can be solved.

在这个快速教程中,我们将了解导致java.lang.OutOfMemoryError:Permgen space错误以及如何解决这个问题。

2. Java Memory Types

2.Java内存类型

The JVM works with two types of memory: the stack and the heap. The stack is used only to store primitive types and object addresses. The heap instead contains the value of the objects. When we talk about memory errors, we always refer to the heap. PermGen is, in fact, part of the heap memory but is separated and handled differently from the main memory of the JVM. The most important concept to grasp is that it is possible to have a lot of available space remaining in a heap and still running out of perm gen memory.

JVM使用两种类型的内存工作:堆栈和。堆栈仅用于存储原始类型和对象地址。而堆则包含了对象的值。当我们谈论内存错误时,我们总是提到堆。事实上,PermGen是堆内存的一部分,但它与JVM的主内存分开并以不同的方式处理。需要掌握的最重要的概念是,有可能在堆中剩余大量的可用空间,但仍然耗尽perm gen内存。

The principal scope of the PermGen is to store the static content of a Java Application Runtime: in particular, among other things, it contains static methods, static variables, references to static objects, and class files.

PermGen的主要范围是存储Java应用程序运行时的静态内容:特别是,除其他外,它包含静态方法、静态变量、对静态对象的引用和类文件。

3. java.lang.OutOfMemoryError: PermGen

3.java.lang.OutOfMemoryError PermGen

Simply put, this error occurs when the space allocated for the PermGen is no longer capable of storing objects. This happens because PermGen is not dynamically allocated and has a fixed maximum capability. The default size is 82 Mb for 64-bit version JVM and 64 Mb for old 32-bit JVM.

简单地说,当分配给PermGen的空间不再能够存储对象时,就会发生这个错误。这是因为PermGen不是动态分配的,它有一个固定的最大容量。64位版本的JVM的默认大小是82Mb,旧的32位JVM是64Mb。

One of the most frequent reasons for the exhaustion of the PemGen is memory leaks related to classloaders. In fact, PermGen contains class files, and classloaders are responsible for loading Java Classes. Classloader issues are frequent in application servers where multiple classloaders are instantiated to achieve the independent deployment of various applications.

PemGen耗尽的最常见原因之一是与classloaders有关的内存泄漏。事实上,PermGen包含类文件,而classloaders负责加载Java Classes。类加载器问题在应用服务器中经常出现,在这些服务器中,多个类加载器被实例化以实现各种应用的独立部署。

Problems arise when an application gets undeployed, and the server container keeps a reference of one or more classes. If this happens, the class loader itself cannot be garbage collected, thus saturating the PermGen memory with his class files. Another common reason for PermGen breakdown is application threads that continue to run after an application gets undeployed, thus maintaining several objects allocated in memory.

当一个应用程序被取消部署,而服务器容器保持一个或多个类的引用时,问题就会出现。如果发生这种情况,类加载器本身就不能被垃圾回收,从而使PermGen内存中的类文件饱和。PermGen崩溃的另一个常见原因是应用程序线程在应用程序被取消部署后继续运行,从而维持了内存中分配的几个对象。

4. Dealing with the Error

4.处理错误

4.1. Tune the Right JVM parameters

4.1.调整正确的JVM参数

The first thing to do regarding limited memory spaces is to increase that space if possible. By using specific flags, the default size of the PermGen space can be increased. Big applications with thousands of classes or a huge number of Java Strings usually need a bigger PermGen space. By using the JVM parameterXX:MaxPermSize is possible to specify a bigger space to allocate for this memory area. 

关于有限的内存空间,首先要做的是尽可能地增加该空间。通过使用特定的标志,PermGen空间的默认大小可以被增加。拥有数千个类或大量Java字符串的大型应用程序通常需要一个更大的PermGen空间。通过使用JVM参数XX:MaxPermSize,可以为这个内存区域指定一个更大的空间来分配。

Since we mentioned JVM flags, It’s also worth mentioning a not-so-used flag that can trigger this error. The –Xnoclassgc JVM parameter, when specified at the start of the JVM, explicitly removes class files from the list of entities to be trashed. In application servers and with modern frameworks that load and unload classes thousands of times per application’s lifecycle, this can bring to very fast exhaustion of the PermGen space.

既然我们提到了JVM标志,那么也值得一提的是一个不太常用的标志,它可以触发这个错误。XnoclassgcJVM参数,当在JVM开始时指定,明确地将类文件从要销毁的实体列表中移除。在应用程序服务器和现代框架中,每个应用程序的生命周期都会加载和卸载数千次类,这可能会导致PermGen空间的快速耗尽。

In older versions of Java, classes are a permanent part of the heap, meaning that once loaded, they remain in memory. By specifying the CMSClassUnloadingEnabled (for Java 1.5 or CMSPermGenSweepingEnabled for Java 1.6) JVM Parameter, it is possible to enable the garbage collection of classes. If we happen to be working with Java 1.6, UseConcMarkSweepGC must also be set to true. Otherwise, the CMSClassUnloadingEnabled argument would be ignored. 

在旧版本的Java中,类是堆的永久组成部分,这意味着一旦加载,它们就会留在内存中。通过指定CMSClassUnloadingEnabled(针对Java 1.5或CMSPermGenSweepingEnabled针对Java 1.6)JVM参数,可以启用类的垃圾收集。如果我们碰巧使用的是Java 1.6,UseConcMarkSweepGC也必须被设置为true。否则,CMSClassUnloadingEnabled参数将被忽略。

4.2. Upgrading to JVM 8+

4.2.升级到JVM 8+

Another way of fixing this kind of error is by upgrading to a newer version of Java. Starting with Java version 8, Permgen has been entirely replaced by Metaspace, which has an automatically resizable space and an advanced feature that enables the cleaning of dead classes. 

修复这种错误的另一种方法是升级到较新的Java版本。从Java版本8开始,Permgen已经完全被Metaspace取代,它有一个可自动调整大小的空间和一个高级功能,能够清理死类。

4.3. Heap Analysis

4.3.堆积分析

It should be trivial noticing that in case of a memory leak, none of the solutions provided can suffice. Memory will finish, no matter how great the size. Even Metaspace has a limited amount of memory available. Deep HEAP analysis is sometimes the only solution and can be conducted with tools like VisualGC or JPROFILER.

应该注意到,在内存泄漏的情况下,所提供的解决方案都不够用。内存将被耗尽,无论规模有多大。即使是Metaspace的可用内存也是有限的。深入的HEAP分析有时是唯一的解决方案,可以用VisualGC或JPROFILER等工具进行。

5. Summary

5.摘要

In this quick write-up, we have seen the purpose of PermGen memory and the main difference with heap memory. Next, we have seen what the java.lang.OutOfMemoryError: Permgen error means and in what peculiar cases gets triggered. In the last section, we focused on the various solutions we can put into play when trying to solve this peculiar problem.

在这篇快速的文章中,我们已经看到了PermGen内存的目的以及与堆内存的主要区别。接下来,我们看到了java.lang.OutOfMemoryError:Permgen错误的含义,以及在哪些特殊情况下会被触发。在最后一节中,我们重点讨论了在试图解决这一特殊问题时,我们可以采用的各种解决方案。