当前位置: 首页 > 后端技术 > Java

jvmcpu和内存问题的常见分析方法

时间:2023-04-02 02:00:01 Java

Java程序在运行过程中经常会遇到CPU或内存占用过高的问题,那么如何排查问题的原因,本文简单介绍一下分析和排查方法。方法一、命令方式分析1、查看占用CPU的进程使用top命令查找CPU和内存占用率最高的进程,获取进程PID。(大写开启时按P键或大写不开启时按shift+P键,会按照CPU使用率排序,大写开启时按M键或大写不开启时按shift+M键,会按照内存占用高低排序)2.使用命令top-H-pPID查找实际占用最高的线程,其中PID就是上一步得到的进程PID,通过这个命令可以查看到实际占用CPU最高的线程的ID。这里会有几个TID。3、获取对应线程的线程堆栈信息,使用命令printf"%x\n"tid,将线程ID转换为16进制。使用命令jstackPID(processpid)|greptid(threadpidinhexadecimal)-A50,这个tid就是上一步转换后的16进制。使用该命令可以查看对应线程的线程栈信息,根据线程栈分析对应的代码。方法二、dump文件分析1.dump文件输出jmap-dump:live,format=b,file=20170307.dump9729file后面是自定义的文件名,最后的数字是进程pid2.使用jvisualvm分析dumpfile:jvisualvm是JDK自带的Java性能分析工具。在JDK的bin目录下,文件名为jvisualvm.exe。jvisualvm可以监控本地和远程java进程,实时查看进程的cpu、heap、thread等参数,生成java进程的dump文件,并对dump文件进行分析。使用方法:直接双击打开jvisualvm.exe,点击File->Load,在文件类型栏选择heap,选择要分析的dump文件,打开。加载完成后,可以在界面右侧的summary、class等选项卡中看到dump文件生成时的heap信息。可以看到dump文件中记录的heapinstances总大小约为300M,(使用第一行的instancesize除以百分比即可),和默认的newgenerationsize差不多JVM的最大堆内存,并且远小于JVM中设置的最大堆内存。也就是说,当达到最大堆内存时,转储文件不会记录实例大小。状态。为了验证,我在本地模拟了堆内存溢出的情况,用jvisualvm进行监控。分析:红框中的部分是发生堆内存溢出时的情况,使用的堆大小(蓝色部分)并没有增加特别明显,但是申请的堆大小(黄色部分)从默认400M多到800M,然后内存溢出了,但是heapsize还是没有增加多少。所以dump文件中的实例列表其实反映了堆的使用情况,只是堆内存的使用没有达到预设的最大堆内存,而是在申请堆内存的过程中超过了预设的最大堆内存。然后内存不足。通过分析Dump文件,可以找出程序中哪里出现了死锁。为什么会出现OOM(OutOfMemory)?一般是这些问题导致分配太少:JVM初始化内存小,业务占用内存大;或者不同JVM区域内存分配不合理。但是分配后不释放,导致内存耗尽,内存泄漏:已经申请的内存没有释放,导致虚拟机无法再次使用该内存,这时候这块内存就泄漏了.因为申请者不再使用了,不能被虚拟机分配给别人。内存溢出:申请的内存超过了JVM所能提供的内存大小。这时候,就叫做溢出。内存泄漏持续存在,最终会溢出。两者是常见的OOM类型因果关系如下:java.lang.OutOfMemoryError:PermGenspaceJava7永久代(方法区)溢出,用于存放类信息,常量,静态变量,以及虚拟加载的即时编译编译机后码等数据。每当第一次加载一个类时,元数据都会存储在永久代中,通常出现在大量的Class对象或JSP页面中,或者是使用CgLib动态代理技术造成的。java8将永久代改为metaspace,报错:java.lang.OutOfMemoryError:Metadataspace,metaspace内存不足,默认动态扩容。我们可以通过-XX:PermSize和-XX:MaxPermSize修改方法区的大小如果堆栈大小设置得太小,也会发生溢出。可以通过-Xss设置栈大小,虚拟机会抛出栈溢出错误,可以在日志中定位错误的类和方法。java.lang.OutOfMemoryError:Java堆空间堆内存溢出。溢出的原因一般是由于JVM堆内存设置不合理或内存泄漏。如果是内存泄漏,可以通过工具查看泄漏对象到GCRoots的引用链。通过掌握泄漏对象的类型信息和GCRoots的引用链信息,可以精确定位泄漏代码的位置。如果没有内存泄漏,也就是内存中的对象一定还活着,那么就应该查看虚拟机的堆参数(-Xmx和-Xms),看看虚拟机的内存是否可以增加.如果在线遇到JVM内存溢出,可以按照以下步骤进行排查:1.jmap-heapPID查看内存分配是否过小。2.jmap-histo:livePID|more检查是否有明显的对象分配过多而没有释放。3.jmap-dump:file=./jvmdump.hprofPID导出JVM当前内存快照,使用JDK或MAT等工具分析快照。如果以上都不能定位问题,则需要检查应用程序是否在不断地创建资源,如网络连接或线程等,可能导致系统资源耗尽。