博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Metaspace 之二--PermGen vs. Metaspace 运行时比较
阅读量:6186 次
发布时间:2019-06-21

本文共 3702 字,大约阅读时间需要 12 分钟。

PermGen vs. Metaspace 运行时比较

  为了更好地理解Metaspace内存空间的运行时行为,

  将进行以下几种场景的测试:

  1. 使用JDK1.7运行Java程序,监控并耗尽默认设定的85MB大小的PermGen内存空间。

  2. 使用JDK1.8运行Java程序,监控新Metaspace内存空间的动态增长和垃圾回收过程。

  3. 使用JDK1.8运行Java程序,模拟耗尽通过“MaxMetaspaceSize”参数设定的128MB大小的Metaspace内存空间。

首先建立了一个模拟PermGen OOM的代码

public class ClassA {    public void method(String name) {    }}

上面是一个简单的ClassA,把他编译成class字节码放到D:/classes下面,测试代码中用URLClassLoader来加载此类型上面类编译成class

package java8;import java.io.File;import java.lang.management.ClassLoadingMXBean;import java.lang.management.ManagementFactory;import java.net.URL;import java.net.URLClassLoader;import java.util.ArrayList;import java.util.List;public class OOMTest {    public static void main(String[] args) {          try{              //准备url              URL url = new File("D:/classes").toURI().toURL();              URL[] urls = {url};              //获取有关类型加载的JMX接口              ClassLoadingMXBean loadingBean = ManagementFactory.getClassLoadingMXBean();              //用于缓存类加载器              List
classLoaders = new ArrayList
(); while(true) { //加载类型并缓存类加载器实例 ClassLoader classLoader = new URLClassLoader(urls); classLoaders.add(classLoader); classLoader.loadClass("ClassA"); //显示数量信息(共加载过的类型数目,当前还有效的类型数目,已经被卸载的类型数目) System.out.println("total: "+ loadingBean.getTotalLoadedClassCount()); System.out.println("active: "+ loadingBean.getLoadedClassCount()); System.out.println("unloaded: "+ loadingBean.getUnloadedClassCount()); } } catch(Exception e) { e.printStackTrace(); } }}

虚拟机器参数设置如下:-verbose -verbose:gc

设置-verbose参数是为了获取类型加载和卸载的信息

设置-verbose:gc是为了获取垃圾收集的相关信息

 

JDK 1.7 @64-bit – PermGen 耗尽测试

Java1.7的PermGen默认空间为85 MB(或者可以通过-XX:MaxPermSize=XXXm指定)

可以从上面的JVisualVM的截图看出:当加载超过6万个类之后,PermGen被耗尽。我们也能通过程序和GC的输出观察耗尽的过程。

程序输出(摘取了部分)

  1. ......  
  2. [Loaded ClassA from file:/D:/classes/]  
  3. total: 64887 
  4. active: 64887 
  5. unloaded: 
  6. [GC 245041K->213978K(536768K), 0.0597188 secs]  
  7. [Full GC 213978K->211425K(644992K), 0.6456638 secs]  
  8. [GC 211425K->211425K(656448K), 0.0086696 secs]  
  9. [Full GC 211425K->211411K(731008K), 0.6924754 secs]  
  10. [GC 211411K->211411K(726528K), 0.0088992 secs]  
  11. ...............  
  12. java.lang.OutOfMemoryError: PermGen space 

JDK 1.8 @64-bit – Metaspace大小动态调整测试

Java的Metaspace空间:不受限制 (默认)

从上面的截图可以看到,JVM Metaspace进行了动态扩展,本地内存的使用由20MB增长到646MB,以满足程序中不断增长的类数据内存占用需求。我们也能观察到JVM的垃圾回收事件—试图销毁僵死的类或类加载器对象。但是,由于我们程序的泄漏,JVM别无选择只能动态扩展Metaspace内存空间。程序加载超过10万个类,而没有出现OOM事件。

JDK 1.8 @64-bit – Metaspace 受限测试

Java的Metaspace空间:128MB(-XX:MaxMetaspaceSize=128m)

可以从上面的JVisualVM的截图看出:当加载超过2万个类之后,Metaspace被耗尽;与JDK1.7运行时非常相似。我们也能通过程序和GC的输出观察耗尽的过程。另一个有趣的现象是,保留的原生内存占用量是设定的最大大小两倍之多。这可能表明,如果可能的话,可微调元空间容量大小策略,来避免本地内存的浪费。

从Java程序的输出中看到如下异常。

  1. [Loaded ClassA from file:/D:/classes/]  
  2. total: 21393 
  3. active: 21393 
  4. unloaded: 
  5. [GC (Metadata GC Threshold) 64306K->57010K(111616K), 0.0145502 secs]  
  6. [Full GC (Metadata GC Threshold) 57010K->56810K(122368K), 0.1068084 secs]  
  7. java.lang.OutOfMemoryError: Metaspace 

在设置了MaxMetaspaceSize的情况下,该空间的内存仍然会耗尽,进而引发“java.lang.OutOfMemoryError: Metadata space”错误。因为类加载器的泄漏仍然存在,而通常Java又不希望无限制地消耗本机内存,因此设置一个类似于MaxPermSize的限制看起来也是合理的。

总结

  1. 之前不管是不是需要,JVM都会吃掉那块空间……如果设置得太小,JVM会死掉;如果设置得太大,这块内存就被JVM浪费了。理论上说,现在你完全可以不关注这个,因为JVM会在运行时自动调校为“合适的大小”;
  2. 提高Full GC的性能,在Full GC期间,Metadata到Metadata pointers之间不需要扫描了,别小看这几纳秒时间;
  3. 隐患就是如果程序存在内存泄露,像OOMTest那样,不停的扩展metaspace的空间,会导致机器的内存不足,所以还是要有必要的调试和监控。

 

总结

  • Hotspot中的元数据现在存储到了元空间里。mmap中的内存块的生命周期与类加载器的一致。
  • 类指针压缩空间(Compressed class pointer space)目前仍然是固定大小的,但它的空间较大
  • 可以进行参数的调优,不过这不是必需的。
  • 未来可能会增加其它的优化及新特性。比如, 应用程序类数据共享;新生代GC优化,G1回收器进行类的回收;减少元数据的大小,以及JVM内部对象的内存占用量。

转载地址:http://vmada.baihongyu.com/

你可能感兴趣的文章
20155301 Makefile和MyOD和共享库
查看>>
HttpClient请求
查看>>
打造一个有感觉的Vim(二)
查看>>
C Looooops 同余方程(扩展欧几里得算法)
查看>>
Nginx负载均衡
查看>>
一个ClientDataset的Delta与XML相互转换
查看>>
针对开发项目的NABCD的分析
查看>>
pe结构讲解
查看>>
ndk build 的时候报错,少了libncurses.so.5
查看>>
Promise的基本用法
查看>>
波特率计算
查看>>
c程序设计语言第一章5
查看>>
四种简单的排序算法
查看>>
RestTemplate常用的get和post带参数请求
查看>>
Scala学习笔记 - 特质
查看>>
总结常见疑问
查看>>
db2 reorg table failed处理
查看>>
1009 Product of Polynomials
查看>>
对拍BAT
查看>>
[20171031]rman xxx Failure.txt
查看>>