文章目录[隐藏]
在 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 中,这些类会大量创建直至充满物理机内存,进而导致进程被系统杀掉。
在系统升级的时候还是要谨慎点,一定要做好预研,尽量避免这种由于机制变化导致的系统问题。