Metaspace 之二--PermGen vs. Metaspace 运行时比较
PermGen vs. Metaspace 运行时比较
为了更好地理解Metaspace内存空间的运行时行为,
将进行以下几种场景的测试:
使用JDK1.7运行Java程序,监控并耗尽默认设定的85MB大小的PermGen内存空间。
使用JDK1.8运行Java程序,监控新Metaspace内存空间的动态增长和垃圾回收过程。
使用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<ClassLoader> classLoaders = new ArrayList<ClassLoader>();
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的输出观察耗尽的过程。
程序输出(摘取了部分)
- ......
- [Loaded ClassA from file:/D:/classes/]
- total: 64887
- active: 64887
- unloaded: 0
- [GC 245041K->213978K(536768K), 0.0597188 secs]
- [Full GC 213978K->211425K(644992K), 0.6456638 secs]
- [GC 211425K->211425K(656448K), 0.0086696 secs]
- [Full GC 211425K->211411K(731008K), 0.6924754 secs]
- [GC 211411K->211411K(726528K), 0.0088992 secs]
- ...............
- 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程序的输出中看到如下异常。
- [Loaded ClassA from file:/D:/classes/]
- total: 21393
- active: 21393
- unloaded: 0
- [GC (Metadata GC Threshold) 64306K->57010K(111616K), 0.0145502 secs]
- [Full GC (Metadata GC Threshold) 57010K->56810K(122368K), 0.1068084 secs]
- java.lang.OutOfMemoryError: Metaspace
在设置了MaxMetaspaceSize的情况下,该空间的内存仍然会耗尽,进而引发“java.lang.OutOfMemoryError: Metadata space”错误。因为类加载器的泄漏仍然存在,而通常Java又不希望无限制地消耗本机内存,因此设置一个类似于MaxPermSize的限制看起来也是合理的。
总结
- 之前不管是不是需要,JVM都会吃掉那块空间……如果设置得太小,JVM会死掉;如果设置得太大,这块内存就被JVM浪费了。理论上说,现在你完全可以不关注这个,因为JVM会在运行时自动调校为“合适的大小”;
- 提高Full GC的性能,在Full GC期间,Metadata到Metadata pointers之间不需要扫描了,别小看这几纳秒时间;
- 隐患就是如果程序存在内存泄露,像OOMTest那样,不停的扩展metaspace的空间,会导致机器的内存不足,所以还是要有必要的调试和监控。
总结
- Hotspot中的元数据现在存储到了元空间里。mmap中的内存块的生命周期与类加载器的一致。
- 类指针压缩空间(Compressed class pointer space)目前仍然是固定大小的,但它的空间较大
- 可以进行参数的调优,不过这不是必需的。
- 未来可能会增加其它的优化及新特性。比如, 应用程序类数据共享;新生代GC优化,G1回收器进行类的回收;减少元数据的大小,以及JVM内部对象的内存占用量。
Metaspace 之二--PermGen vs. Metaspace 运行时比较的更多相关文章
- 日志系统实战(二)-AOP动态获取运行时数据
介绍 这篇距上一篇已经拖3个月之久了,批评自己下. 通过上篇介绍了解如何利用mono反射代码,可以拿出编译好的静态数据.例如方法参数信息之类的. 但实际情况是往往需要的是运行时的数据,就是用户输入等外 ...
- 《深入理解Java虚拟机》(二)Java虚拟机运行时数据区
Java虚拟机运行时数据区 详解 2.1 概述 本文参考的是周志明的 <深入理解Java虚拟机>第二章 ,为了整理思路,简单记录一下,方便后期查阅. 2.2 运行时数据区域 Java虚拟机 ...
- (二)、JAVA运行时数据区域
根据<Java 虚拟机规范(Java SE 7版)>规定,Java虚拟机所管理的内存,将会包括以下几个运行时数据区域: 注: 1.由所有线程共享的数据区: 对应 java内存模型的主内存, ...
- .net开发笔记(十二) 设计时与运行时的区别(续)
上一篇博客详细讲到了设计时(DesignTime)和运行时(RunTime)的概念与区别,不过没有给出实际的Demo,今天整理了一下,做了一个例子,贴出来分享一下,巩固前一篇博客讲到的内容. 简单回顾 ...
- openmp学习心得(二)----常见的运行时库函数
omp_set_dynamic();如果设置了动态调整,并行区域会根据系统的资源状况,动态分配线程的数量.好像仅仅有0和非0的区别,设置为0不进行动态分配. omp_get_num_threads,o ...
- Metaspace 之二--Java 8的元空间(metaspace)、metaspace监控方法
很多开发者都在其系统中见过“java.lang.OutOfMemoryError: PermGen space”这一问题.这往往是由类加载器相关的内存泄漏以及新类加载器的创建导致的,通常出现于代码热部 ...
- 聊聊jvm的PermGen与Metaspace
转载:https://segmentfault.com/a/1190000012577387 序 本文主要讲述一下jvm的PermGen与Metaspace java memory结构 分代概念 对于 ...
- JVM 运行时数据区(二)
@ 目录 运行时数据区 共享区 堆区 方法区 隔离区 虚拟机栈 栈帧 本地方法栈 程序计数器 运行时数据区 JVM 运行时数据区主要分为5块 方法区 JDK1.8以后叫做元数据区(Metaspace) ...
- Java虚拟机详解(二)------运行时内存结构
首先通过一张图了解 Java程序的执行流程: 我们编写好的Java源代码程序,通过Java编译器javac编译成Java虚拟机识别的class文件(字节码文件),然后由 JVM 中的类加载器加载编译生 ...
随机推荐
- Java内存模型之总结
经过四篇博客阐述,我相信各位对Java内存模型有了最基本认识了,下面LZ就做一个比较简单的总结. 总结 JMM规定了线程的工作内存和主内存的交互关系,以及线程之间的可见性和程序的执行顺序.一方面,要为 ...
- iOS动画:CAKeyframeAnimation
网络中Core Animation类的继承关系图 属性简介 @interface CAKeyframeAnimation : CAPropertyAnimation /* 提供关键帧数据的 ...
- 善用#waring,#pragma mark 标记
在项目开发中,我们不可能对着需求一口气将代码都写好.开发过程中肯定遇到诸如需求变动,业务逻辑沟通,运行环境的切换等这些问题.当项目大的时候,如果木有形成统一的代码规范,在项目交接和开发人员沟通上将会带 ...
- kali linux Desktop Environemt types and kali linux install virualbox
1.we know the kali linux desktop environmet can also be costomized ,Desktop environmet can use GNOME ...
- Django 使用form组件对文件上传
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Vue项目打包发布,配置Nginx
#user nobody; worker_processes 1; #error_log logs/error.log; #error_log logs/error.log notice; #erro ...
- Codeforces Round #525 (Div. 2) D. Ehab and another another xor problem(交互题 异或)
题目 题意: 0≤a,b<2^30, 最多猜62次. 交互题,题目设定好a,b的值,要你去猜.要你通过输入 c d : 如果 a^c < b^d ,会反馈 -1 : 如果 a^c = b^ ...
- ACM-ICPC 2018 徐州赛区网络预赛 A. Hard to prepare (组合数学,递归)
A. Hard to prepare After Incident, a feast is usually held in Hakurei Shrine. This time Reimu asked ...
- 【loj-1055-Going Together-三个棋子推箱子走到目的地--讲预判的bfs】
light oj 1055-Going Together 题目大致意思: 简单的三个棋子,每次可以下达一个命令,robots全部按照指令进行前进:若下一步不为空地则停留在原地. 特殊考虑: 1.例如A ...
- Oracle中split功能的实现
原始需求: 有这样的表:tb和pk两列 PK是将表的多个主键用“|”进行分隔,我想把它变成多行 如 fundamentals_asia1_af_out ID_BB_GLOBAL|BC_DT|BC_EQ ...