As you may be aware, the JDK 8 Early Access is now available for download. This allows Java developers to experiment with some of the new language and runtime features of Java 8. One of these features is the complete removal of the Permanent Generation (PermGen) space which has been announced by Oracle since the release of JDK 7. Interned strings, for example, have already been removed from the PermGen space since JDK 7. The JDK 8 release finalizes its decommissioning. This article will share the information that we found so far on the PermGen successor: Metaspace. We will also compare the runtime behavior of the HotSpot 1.7 vs. HotSpot 1.8 (b75) when executing a Java program “leaking” class metadata objects. The final specifications, tuning flags and documentation around Metaspace should be available once Java 8 is officially released.
Metaspace:
A new memory space is born
The JDK 8 HotSpot JVM is now using native memory for the representation of class metadata and is called Metaspace; similar to the Oracle JRockit and IBM JVM’s. The good news is that it means no more java.lang.OutOfMemoryError: PermGen space problems and no need for you to tune and monitor this memory space anymore…not so fast. While this change is invisible by default, we will show you next that you will still need to worry about the class metadata memory footprint. Please also keep in mind that this new feature does not magically eliminate class and classloader memory leaks. You will need to track down these problems using a different approach and by learning the new naming convention. I recommend that you read the PermGen removal summary and comments from Jon on this subject.
In summary:
PermGen space situation
- This memory space is completely removed.
- The PermSize and MaxPermSize JVM arguments are ignored and a warning is issued if present at start-up.
Metaspace memory allocation model
- Most allocations for the class metadata are now allocated out of native memory.
- The klasses that were used to describe class metadata have been removed.
Metaspace capacity
- By default class metadata allocation is limited by the amount of available native memory (capacity will of course depend if you use a 32-bit JVM vs. 64-bit along with OS virtual memory availability).
- A new flag is available (MaxMetaspaceSize), allowing you to limit the amount of native memory used for class metadata. If you don’t specify this flag, the Metaspace will dynamically re-size depending of the application demand at runtime.
Metaspace garbage collection
- Garbage collection of the dead classes and classloaders is triggered once the class metadata usage reaches the “MaxMetaspaceSize”.
- Proper monitoring & tuning of the Metaspace will obviously be required in order to limit the frequency or delay of such garbage collections. Excessive Metaspace garbage collections may be a symptom of classes, classloaders memory leak or inadequate sizing for your application.
Java heap space impact
- Some miscellaneous data has been moved to the Java heap space. This means you may observe an increase of the Java heap space following a future JDK 8 upgrade.
Metaspace monitoring
- Metaspace usage is available from the HotSpot 1.8 verbose GC log output.
- Jstat & JVisualVM have not been updated at this point based on our testing with b75 and the old PermGen space references are still present.
Enough theory now, let’s see this new memory space in action via our leaking Java program…
PermGen vs. Metaspace runtime comparison
In order to better understand the runtime behavior of the new Metaspace memory space, we created a class metadata leaking Java program. You can download the source here.
The following scenarios will be tested:
- Run the Java program using JDK 1.7 in order to monitor & deplete the PermGen memory space set at 128 MB.
- Run the Java program using JDK 1.8 (b75) in order to monitor the dynamic increase and garbage collection of the new Metaspace memory space.
- Run the Java program using JDK 1.8 (b75) in order to simulate the depletion of the Metaspace by setting the MaxMetaspaceSize value at 128 MB.
JDK 1.7 @64-bit – PermGen depletion
- Java program with 50K configured iterations
- Java heap space of 1024 MB
- Java PermGen space of 128 MB (-XX:MaxPermSize=128m)
As you can see form JVisualVM, the PermGen depletion was reached after loading about 30K+ classes. We can also see this depletion from the program and GC output.
1 |
Class metadata leak simulator |
2 |
3 |
Author: Pierre-Hugues Charbonneau |
4 |
6 |
7 |
ERROR: java.lang.OutOfMemoryError: PermGen space |
Now let’s execute the program using the HotSpot JDK 1.8 JRE.
JDK 1.8 @64-bit – Metaspace dynamic re-size
- Java program with 50K configured iterations
- Java heap space of 1024 MB
- Java Metaspace space: unbounded (default)
As you can see from the verbose GC output, the JVM Metaspace did expand dynamically from 20 MB up to 328 MB of reserved native memory in order to honor the increased class metadata memory footprint from our Java program. We could also observe garbage collection events in the attempt by the JVM to destroy any dead class or classloader object. Since our Java program is leaking, the JVM had no choice but to dynamically expand the Metaspace memory space. The program was able to run its 50K of iterations with no OOM event and loaded 50K+ Classes. Let’s move to our last testing scenario.
JDK 1.8 @64-bit – Metaspace depletion
- Java program with 50K configured iterations
- Java heap space of 1024 MB
- Java Metaspace space: 128 MB (-XX:MaxMetaspaceSize=128m)
As you can see form JVisualVM, the Metaspace depletion was reached after loading about 30K+ classes; very similar to the run with the JDK 1.7. We can also see this from the program and GC output. Another interesting observation is that the native memory footprint reserved was twice as much as the maximum size specified. This may indicate some opportunities to fine tune the Metaspace re-size policy, if possible, in order to avoid native memory waste.
Now find below the Exception we got from the Java program output.
1 |
Class metadata leak simulator |
2 |
3 |
Author: Pierre-Hugues Charbonneau |
4 |
6 |
7 |
ERROR: java.lang.OutOfMemoryError: Metadata space |
Done!
As expected, capping the Metaspace at 128 MB like we did for the baseline run with JDK 1.7 did not allow us to complete the 50K iterations of our program. A new OOM error was thrown by the JVM. The above OOM event was thrown by the JVM from the Metaspace following a memory allocation failure.
#metaspace.cpp
Final words
I hope you appreciated this early analysis and experiment with the new Java 8 Metaspace. The current observations definitely indicate that proper monitoring & tuning will be required in order to stay away from problems such as excessive Metaspace GC or OOM conditions triggered from our last testing scenario. Future articles may include performance comparisons in order to identify potential performance improvements associated with this new feature.
相关推荐
Java 8 中引入了一个新的内存区域Metaspace,取代了PermGen空间,解决了PermGen频繁发生的OutOfMemoryError问题。 #### 十、StampedLock将是解决同步问题的新宠 **StampedLock**: - **定义**:是一种新型的锁机制...
2. **PermGen Space**:当方法区(永久代)空间不足时,抛出`OutOfMemoryError: PermGen space`。在JDK 8中,由于永久代被元空间替换,此问题已不再出现。 #### 八、总结 Java内存模型的设计是为了高效地管理内存...
- **方法区(Method Area)/永久代(PermGen):** 也称为元空间(Metaspace)在较新的JVM版本中,存储类信息、常量、静态变量等。这部分是线程共享的。 - **Java堆(Heap):** 是所有对象的诞生地,用于存储对象...
- **PermGen/Metaspace Overflow**:持久代/元空间溢出,通常由于过多的类或大型静态变量引起,可通过增大相应区域大小或限制类加载。 9. **JIT编译器(Just-In-Time Compiler)**: - **HotSpot** JVM包含C1和C2...
在Java 8之后,永久代被元空间(Metaspace)所替代,元空间位于本地内存中。 了解JVM的内存管理机制对于有效地管理和优化Java应用程序的性能非常重要。通过合理地配置JVM参数,可以显著提升程序的运行效率。例如,...
- 不同于堆,方法区在JVM规范中被称为永久代(PermGen space),但在Java 8之后改名为Metaspace,并且移至本机内存。 - 方法区同样可能发生`OutOfMemoryError`。 5. **本地方法栈(Native Method Stack)** - **定义...
- **PermGen/元空间大小**:在Java 8之前,`XX:PermSize`和`XX:MaxPermSize`用于设置永久代大小;在Java 8及以上,元空间大小由系统决定,但可以通过操作系统参数限制。 - **线程栈大小**:`-Xss`参数设定每个...
在Java 8及以前版本中被称为永久代(PermGen space),但在Java 8中被元空间(Metaspace)取代。元空间并不在Java堆中,而是使用本地内存。因此理论上其大小仅受物理内存限制。 - **本地方法栈(Native Method ...
10. **JVM内存溢出问题**:常见的有堆溢出(OOM: OutOfMemoryError - heap space)、 PermGen/元空间溢出、方法区溢出等,需要合理设置JVM参数并优化代码以避免。 通过掌握以上知识点,Java开发者不仅可以编写高...
- **永久代( Perm Gen space)**:在早期JVM版本中,用来存储类元数据,但在现代JVM(如Java 8及之后版本)中已被元空间(Metaspace)取代。 4. **内存泄漏**: - 在Java中,内存泄漏通常是指不再被程序使用的...
如果PermGen空间(Java 8之前的版本)或Metaspace(Java 8及之后版本)过小,可能会导致频繁的GC活动,甚至出现OutOfMemoryError异常。 5. **常用的GC回收算法有哪些?** 常用的GC回收算法包括但不限于:串行收集...
方法区主要用于存放类信息、常量、静态变量等,它在JDK中对应的是持久代(Permanent Generation,PermGen),可以通过JVM参数-XX:PermSize和-XX:MaxPermSize来指定其最小值和最大值。由于方法区的垃圾收集并不频繁,...
Java 8之前的PermGen在达到最大值时会抛出`OutOfMemoryError`,而元空间使用的是操作系统的本地内存,理论上可以无限大,但会受到物理内存限制。 6. **程序计数器**:每个线程都有一个独立的程序计数器,记录当前...
3. **方法区(Method Area)**:在JDK1.7及之前被称为永久代(PermGen),存储类的信息,如类的元数据、常量池、静态变量等。在JDK1.8及以后,永久代被元空间(Metaspace)取代。 4. **程序计数器(Program Counter...
其中,堆内存又可以细分为年轻代(Young Generation)、老年代(Tenured Generation)和永久代( PermGen 或者 Metaspace,取决于JVM版本)。 **年轻代调优** 年轻代是新生对象的驻留地,包括Eden区和两个Survivor...
在JDK 8及之后的版本中,方法区常被称为元空间(Metaspace),它与永久代(PermGen)的主要区别是元空间使用的是本地内存,而永久代使用的是JVM内存。 以上就是关于JVM面试专题的一些关键知识点,通过深入理解和...
堆是Java对象的主要存储区域,分为年轻代(Young Generation)、老年代(Tenured Generation)和永久代(PermGen/Metaspace)。尽管JVM的内存管理不是直接应用Buddy System,但其内存分配和回收的机制有类似的理念。...