标签:Java 堆区 XX 调优 GC 内存 Jvm 日志 public
前言
Java 的性能调优,主要就是为了防止出现out of memory(oom)。Java出现oom就会直接导致程序停止运行。
调优
模拟元空间oom的情况
import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class MetaSpaceOverTest { public static void main(String[] args) throws InterruptedException { while (true){ Thread.sleep(20); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(MetaSpaceOverTest.class); enhancer.setUseCache(false); enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { return methodProxy.invoke(o,objects); } }); enhancer.create(); } } }
需要设置的参数:-XX:+PrintGCDetails -XX:MetaspaceSize=20M -XX:MaxMetaspaceSize=20M 分别是打印GC日志,设置元空间的内存初始值的最大值。
代码中使用了CGLib的jar包:具体说明见:https://www.cnblogs.com/jssj/p/12635206.html
运行结果:
Metaspace 空间出现oom的情况,通过jvisualvm 工具可以比较清楚的看到元空间的使用情况。
GC日志说明:
[GC (Metadata GC Threshold) [PSYoungGen: 555K->128K(35328K)] 4349K->3922K(105472K), 0.0012436 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC (Metadata GC Threshold) [PSYoungGen: 128K->0K(35328K)] [ParOldGen: 3794K->3789K(108544K)] 3922K->3789K(143872K), [Metaspace: 19831K->19831K(1067008K)], 0.0169102 secs] [Times: user=0.02 sys=0.00, real=0.02 secs]
GC (Metadata GC Threshold): 这是一个young GC,表示GC作用的内存位置,Metadata是元空间的意思。
[PSYoungGen: 555K->128K(35328K)] :这是一个youngGC 新生代堆区从555K 变成 128K, 新生代堆区总大小是35328K。
4349K->3922K(105472K) :总堆区从4349K到3922K, 总堆区的大小105472K。
0.0012436 secs:GC消耗的时间。
Full GC (Metadata GC Threshold) : 这是一个Full GC。
[PSYoungGen: 128K->0K(35328K)]:新生代对象占用内存移动到了老年代。
[ParOldGen: 3794K->3789K(108544K)]:老年代堆区从3794K->3789K。
3922K->3789K(143872K):整个堆区的变化情况。
[Metaspace: 19831K->19831K(1067008K)]:元空间的占用内存的变化情况。这里可以看到已经快超20M。
重点:方法区调优,-XX:MetaspaceSize=20M -XX:MaxMetaspaceSize=20M 两个参数设置一样大,程序运行后查询元空间被使用的情况,在这个基础上加20%的。查看元空间的使用情况可以使用工具:jvisualvm
模拟堆区的oom
import java.util.ArrayList; import java.util.List; public class HeapOverTest { int[] intArr = new int[50]; public static void main(String[] args) throws InterruptedException { List<HeapOverTest> heapOverTestList = new ArrayList<>(); for(;;){ Thread.sleep(1); heapOverTestList.add(new HeapOverTest()); } } }
-Xmx10m -Xms10m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:
Jvm 参数设置堆的最大最小内存大小和打印GC日志, 剩下的是用于打印日志和将Heap信息的日志存放到D盘。
运行结果:(运行一段时间会出现这个报错。)
利用该工具可以很好的看出来堆内存的使用情况。
根据前面的信息,我们已经获取到一个HeapOOM的日志,我们来分析看看。
上传日志分析,点击类视图,查看什么对象比较占用内存。
可以比较明显的看出什么比较暂用内存。当然生产环境会比这个大很多很多,分析也会更加复杂。
这里的int[] 我们其实还不知道具体是被哪个对象引用,所以我需要查看被引用对象。
然后找到他的引用对象:
堆区调优:堆区最大值和最小值调整一样大,防止内存抖动,具体调整多大根据程序正常运行下再加30%。
-Xmx10m 设置堆内存的最大值 -Xms10m 设置堆内存的最小值
虚拟机栈-OOM
public class StackOverTest { private int val = 0; public void test(){ val++; test(); } public static void main(String[] args) { StackOverTest stackOverTest = new StackOverTest(); try { stackOverTest.test(); } catch (Throwable e) { System.out.println("栈深度:"+stackOverTest.val); } } }
运行结果:
这个栈深度每次运行会出现略微的差别:原因是因为会出现栈上分配,轻量级锁的存在。
-Xss100K 设置虚拟机栈大小,部分机器最小要求不同
Java Agent
待补充
实战
1. 死锁
2. CPU消耗高
top -H -p 6290 --6290是进程号
总结
Jvm性能调优是Java工程师的必修课。
标签:Java,堆区,XX,调优,GC,内存,Jvm,日志,public 来源: https://www.cnblogs.com/jssj/p/14382863.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。