關于 MetaSpace 內存
在 JDK8 之前挚躯,虛擬機內存主要分為堆和非堆兩部分强衡,堆中劃分新生代老生代,非堆中包含所有非對象信息和運行時信息码荔,其中有一塊叫 PermGen食侮,用以保存字節(jié)碼等類信息。在 JDK8 中取消了這塊內存目胡,并添加了 MetaSpace 替代所有功能。
這兩塊的區(qū)別
最大的區(qū)別就是位置不同大小不同链快,PermGen 仍然歸屬 JVM 內存誉己,一般 32M 或者 64M,都很小域蜗,MetaSpace 直接位于本地內存巨双,默認大小只受物理機限制
噪猾,直到用完物理機內存才拋出 OOM。
所以在某些情況下直接升級 JDK8 可能就出現(xiàn)內存持續(xù)增長的情況筑累,在這種情況下通過 top 命令會發(fā)現(xiàn)內存猛漲袱蜡,遠超 Xmx 設置的大小, 但通過 jmap 則發(fā)現(xiàn)正常慢宗。
例如
先看段 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坪蚁,在序列化對象時會為對象生成代理類,然后通過執(zhí)行代理進行序列化操作镜沽,通過這樣優(yōu)化來提高執(zhí)行性能敏晤,但在應用不合理每次新創(chuàng)建 config 的時候就會導致大量生成代碼類反而拖慢性能。反序列化時的 ParserConfig 也是同理缅茉。
在 jdk8 之前這些代理類會充滿 Perm 區(qū)導致 FullGC嘴脾,浪費點 CPU 也不會有大問題,但在 JDK8 中蔬墩,這些類會大量創(chuàng)建直至充滿物理機內存译打,進而導致進程被系統(tǒng)殺掉。
附 MetaSpace 相關參數(shù)
- -XX:MetaspaceSize拇颅,初始空間大小奏司,達到該值就會觸發(fā)垃圾收集進行類型卸載,同時GC會對該值進行調整:如果釋放了大量的空間蔬蕊,就適當降低該值结澄;如果釋放了很少的空間,那么在不超過MaxMetaspaceSize時岸夯,適當提高該值麻献。
- -XX:MaxMetaspaceSize,最大空間猜扮,默認是沒有限制的勉吻。
- -XX:MinMetaspaceFreeRatio,在GC之后旅赢,最小的Metaspace剩余空間容量的百分比齿桃,減少為分配空間所導致的垃圾收集
- -XX:MaxMetaspaceFreeRatio,在GC之后煮盼,最大的Metaspace剩余空間容量的百分比短纵,減少為釋放空間所導致的垃圾收集