文章目录
- 定位CPU标高
- 内存问题
- JVM参数
- 工具
定位CPU标高
方法1:
1-启动:java -jar 2_cpu-0.0.1-SNAPSHOT.jar 8 > log.file 2>&1 &
2-一般来说,应用服务器通常只部署了java应用,可以top一下先确认,是否是java应用导致的:
命令:top 3-如果是,查看java进场ID,
命令:jps -l 4-找出该进程内最好非CPU的线程,
命令:top -Hp pid 25128 5-将线程ID转化为16进制,
命令:printf “%x\n” 线程ID 623c 25148 6-导出java堆栈信息,根据上一步的线程ID查找结果:命令: jstack 11976 >stack.txt grep 2ed7 stack.txt -A 20 方法
2: 在线工具:https://gceasy.io/ft-index.jsp 1-方法1中导出的对快照文件,上传到该网站即可
内存问题
内存泄漏(Memory Leak)
是指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序
运行速度减慢甚至系统崩溃等严重后果。
一般内存泄露的方式:
- 常发性内存泄漏:发生内存泄漏的代码会被多次执行到,每次被执行时都会导致一块内存泄漏。
- 偶发性内存泄漏:发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。
- 一次性内存泄漏:发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块且仅有一块内存发生泄漏。
- 隐式内存泄漏:程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。从用户使用程序的角度来看,内存泄漏本身不会产生什么危害,作为一般的用户,根本感觉不到内存泄漏的存在。真正有危害的是内存泄漏的堆积,这会最终耗尽系统所有的内存。从这个角度来说,一次性内存泄漏并没有什么危害,因为它不会堆积,而隐式内存泄漏危害性则非常大,因为较之于常发性和偶发性内存泄漏它更难被检测到。
JAVA中的内存泄露:
上面所描述的是通常的内存泄露方式,当然也适用于java,但是对于java而言,问题似乎变得简单了,JAVA的一个重要特性就是通过垃圾收集器(GC)自动管理内存的回收,而不需要程序员自己来释放内存。理论上Java中所有不会再被利用的对象所占用的内存,都可以被GC回收,但是Java也存在内存泄露,但它的表现与C或者C++不同而已。这通常都是设计不合理造成的,也因此通过设计是可以避免的。根本问题在于,是否我们需要掌控的对象,在应该销毁的时候没有销毁,或者没有预料到对象的增量超出我们的预想。
1-对象增长超出预想
2-设计应该销毁的对象,而常驻内存
对于问题一,举一个常见的设计规约:线程池的创建应该显示指定阻塞队列得到小,避免默认值失去控制,极坏的情况下创建了大量的线程,导致OOM。
问题二,经常出现在设计缓存,存储的map,list中,无限增长,失去控制。
常见的容易导致内存泄露的点
1-线程池创建未显示指定阻塞队列大小
2-ThreadLocal 的管理中忘记回收对象
3-所有涉及资源链接的地方,都不要忘记关闭资源
4-类的成员变量为集合,或者单例的模式中有集合,引用了大量的其他对象
5-java方法,是传值还是传引用,造成的小时间段内,内存没按照预想回收掉
内存溢出(Out Of Memory)
内存溢出就是内存越界。内存越界有一种很常见的情况是调用栈溢出(即stackoverflow),虽然这种情况可以看成是栈内存不足的一种体现
内存溢出跟内存泄露区别:
内存溢出:申请内存时,JVM没有足够的内存空间。
内存泄露:申请了内存,但是没有释放,导致内存空间浪费
JVM参数
1-JVM的参数类型
1.1 标配参数:-version,-help
1.2 X参数(了解):-Xint,-Xmixed
1.3 XX参数:
1.3.1 boolean类型:-XX:+PrintGCDetails
1.3.2 KV设值类型:-XX:MetaspaceSize=128m
2-查看内存参数
2.1 -XX:+PrintFlagsInitial 主要查看初始默认(不依赖java进程) case:java -XX:+PrintFlagsInitial
2.2 -XX:+PrintFlagsFinal 主要查看修改更新(不依赖java进程) case:java -XX:+PrintFlagsFinal 2.3 -XX:+PrintCommandLineFlags 打印命令行参数
2.4 jinfo 查看进程相关数据 case: jinfo -flag MetaspaceSize pid 问题: -Xms:初始大小内存,默认物理内存1/64,等价于-XX:InitialHeapSize -Xmx:最大分配内存,默认为物理内存1/4,等价于-XX:MaxHeapSize -Xss:设置单个线程栈的大小,一般默认为512k~1024k,等价于-XX:ThreadStackSize 参考:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
常用配置
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heapdump.txt
-XX:+PrintGCDetails
-Xloggc:gc.log
工具
1-jvm gc日志分析工具:https://javagc.cn/ https://gceasy.io/ft-index.jsp
2-内存快照分析工具:mat,jprofile,VisualVM
3-java自带:
-jps 进程查看
-jstat:用于监视虚拟机各种运行状态信息的命令行工具。可以显示本地或者远程虚拟机进程中的类记载、内存、垃圾收集、JIT编译等运行数据
jstat -gc pid #垃圾回收统计
jstat -gccapacity pid #堆内存统计
jstat -gcnew pid #新生代垃圾回收统计
jstat -gcnewcapacity pid #新生代内存统计
jstat -gcold pid #老年代垃圾回收统计
jstat -gcoldcapacity pid #老年代内存统计 j
stat -gcutil pid #总结垃圾回收统计
jstat -printcompilation pid #JVM编译方法统计
jstat -class pid #类加载统计
-jinfo 参数配置查看
-jmap 内存监控
jmap -clstats pid #打印进程的类加载器和类加载器加载的持久代对象信息
jmap -heap pid #查看进程堆内存使用情况,包括使用的GC算法、堆配置参数和各代中堆内存使用情况。
jmap -histo[:live] pid #查看堆内存中的对象数目、大小统计直方图,如果带上live则只统计活对象
jmap -dump:format=b,file=dumpFileName pid #jmap把进程内存使用情况dump到文件中