文章目录[隐藏]
关于 MetaSpace 内存
在 JDK8 之前,虚拟机内存主要分为堆和非堆两部分,堆中划分新生代老生代,非堆中包含所有非对象信息和运行时信息,其中有一块叫 PermGen,用以保存字节码等类信息。在 JDK8 中取消了这块内存,并添加了 MetaSpace 替代所有功能。
这两块的区别
最大的区别就是位置不同大小不同,PermGen 仍然归属 JVM 内存,一般 32M 或者 64M,都很小,MetaSpace 直接位于本地内存,默认大小只受物理机限制
,直到用完物理机内存才抛出 OOM。
所以在某些情况下直接升级 JDK8 可能就出现内存持续增长的情况,在这种情况下通过 top 命令会发现内存猛涨,远超 Xmx 设置的大小, 但通过 jmap 则发现正常。
例如
先看段 fastjson 的代码:
public void process(HttpServletResponse resp) {
....
SerializeConfig config = new SerializeConfig();
config.put(Long.class, RsLongSerializer.instance);
resp.getWriter().print(JSON.toJSONString(obj,config));
}
这段代码的问题就在 SerializeConfig 默认会激活 asm,在序列化对象时会为对象生成代理类,然后通过执行代理进行序列化操作,通过这样优化来提高执行性能,但在应用不合理每次新创建 config 的时候就会导致大量生成代码类反而拖慢性能。反序列化时的 ParserConfig 也是同理。
在 jdk8 之前这些代理类会充满 Perm 区导致 FullGC,浪费点 CPU 也不会有大问题,但在 JDK8 中,这些类会大量创建直至充满物理机内存,进而导致进程被系统杀掉。
附 MetaSpace 相关参数
- -XX:MetaspaceSize,初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整:如果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过MaxMetaspaceSize时,适当提高该值。
- -XX:MaxMetaspaceSize,最大空间,默认是没有限制的。
- -XX:MinMetaspaceFreeRatio,在GC之后,最小的Metaspace剩余空间容量的百分比,减少为分配空间所导致的垃圾收集
- -XX:MaxMetaspaceFreeRatio,在GC之后,最大的Metaspace剩余空间容量的百分比,减少为释放空间所导致的垃圾收集
All Done!
在系统升级的时候还是要谨慎点,一定要做好预研,尽量避免这种由于机制变化导致的系统问题。
已解决
你好,请您指教一个问题。
我在main方法内写了一个循环,通过readLine来进行阻塞,每次释放代码执行1000次,即
SerializeConfig config = new SerializeConfig();
config.put(Long.class, RsLongSerializer.instance);
JSON.toJSONString(obj,config);
这段代码执行一千次,但是通过jconsole的监控来看,metaspace并无变化,反而是S区一直GC,求指教