Thread Local Area内存溢出的处理方法
时间:2017年3月
坐标:杭州市
事件描述:
业务系统频繁出现服务挂机,一天挂机两三次,分析日志发现如下报错:
报错中的“java.lang.OutOfMemoryError: getNewTla.”是指当前虚拟机不能分配新的线程本地空间(Thread Local Area)。
服务使用的是Oracle JRockit R28版本的jdk,经查阅其原理,它有特有的线程本地空间(Thread Local Area)的机制。
JRockit 默认使用线程本地分配 TLA, 这允许线程不需要同步即可分配对象,这将有利于分配速度, TLA 的大小而且可以配置,大的 TLA 可以优化使用大量线程本地分配对象的应用, 另一方面,太大的 TLA 会导致更多的碎片, 因为 TLA 是被线程以排斥的方式独有的,因此受限于线程数并依赖于应用的架构。
解决方案:
1、调大TLA的值,在jvm启动参数中调整,如:”-XXtlaSize:min=16k,preferred=1024k,wasteLimit=16k“。提高其中的preferred的值。
2、另一个与a方式不同的解决方案:可以利用参数-XXlargeObjectLimit,限制在本地线程创建对象的最大值。
3、另外由于Oracle JRockit 的JDK在运行时会保存已经运行的机器字节码,供以后的运行使用,它会比其他版本的JDK(比如HotSpot、IBM JVM、OpenJDK)所需的内存空间更大。所以建议在允许的情况下提高jvm堆内存大小。这里把系统的jvm堆内存从4G调整为8G。
4、Oracle JRockit 的Heap 策略:使用“分代 Heap ”,而且支持一个所谓的“连续 Heap ”。分代 Heap 分为:老生区( Old/Tenured) 和苗圃 / 新生区( Nursery) ,当对象被申请时,他们被放在一个新生区中称为 Keep Area 的地方, 在 GC 时, Keep Area 不会被考虑而其它仍然存活的对象会被马上移到老生区。因此,新生区的大小是 JRockit 很重要的参数,可调整为与老生区同大小或更大。
jvm启动参数调整案例:
1、-Xms8192m –Xmx8192m -XXtlaSize:min=16k,preferred=2048k,wasteLimit=16k 。
2、-Xms8192m –Xmx8192m -XXtlaSize:min=16k,preferred=512k -XXlargeObjectLimit:16k 。