目录

  • OOM分析
    • Java堆内存溢出
    • 元空间/方法区溢出
  • 线程Dump

OOM分析

Java堆内存溢出

启动参数:

  • -Xms250m -Xmx250m ,最大最小堆内存250m,禁止自动扩展内存
  • -XX:+HeapDumpOnOutOfMemoryError:在发生OOM时进行堆内存Dump生成快照
public class oomController {@RequestMapping(value = "/test", method = RequestMethod.GET)public @ResponseBodyvoid test() {List<TestInst> testInstList = new ArrayList<>();Long i = 0L;while (true) {TestInst testInst = new TestInst();testInstList.add(testInst);}}
}class TestInst {String name;String desc;
}
  • 不不断的创建对象,并且保证GC Roots到对象之间有 可达路路径来避免垃圾回收机制清除这些对象
  • 启动项目并调用上述方法,项目将马上报错内存溢出:
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid98284.hprof ...
Heap dump file created [338473308 bytes in 1.782 secs]
七月 19, 2021 11:09:28 下午 org.apache.catalina.core.StandardWrapperValve invoke
严重: Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.OutOfMemoryError: Java heap space] with root cause
java.lang.OutOfMemoryError: Java heap spaceat java.util.Arrays.copyOf(Arrays.java:3210)at java.util.Arrays.copyOf(Arrays.java:3181)at java.util.ArrayList.grow(ArrayList.java:265)at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:239)at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:231)at java.util.ArrayList.add(ArrayList.java:462)at com.example.gangtie.controller.oomController.test(oomController.java:34)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189)at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:800)at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038)at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897)at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
  • 分析生成的堆dump文件java_pid98284.hprof
    使用JVM自带工具jvisualvm,一般其路径位于$JAVA_PATH/jdk/bin中

元空间/方法区溢出

  • JDK8 中将永久代移除,使用 MetaSpace 来保存类加载之后的类信息
  • JDK 8 中将字符串常量池也被移动到 Java 堆,将原有的永久代移动到了本地堆中成为 MetaSpace
  1. Java7
    抛出永久代溢出 java.lang.OutOfMemoryError:PermGen Space
  2. Java8
    抛出元空间溢出 java.lang.OutOfMemoryError:Metaspace
  • 借助CGLib直接操作字节码运⾏时产⽣生⼤量的动态类, 最终导致内存溢出

启动参数:

  • -XX:MaxMetaspaceSize=100M
@RequestMapping(value = "/test2", method = RequestMethod.GET)public @ResponseBodyvoid test2() {while (true) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(oomController.class);enhancer.setUseCache(false);enhancer.setCallback(new MethodInterceptor() {@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {return methodProxy.invoke(o, objects);}});enhancer.create();}}

线程Dump

  • 调试排错 - Java线程Dump分析
    一般当服务器挂起,崩溃或者性能低下时,就需要抓取服务器的线程堆栈(Thread Dump)用于后续的分析。在实际运行中,往往一次 dump的信息,还不足以确认问题。为了反映线程状态的动态变化,需要接连多次做thread dump,每次间隔10-20s,建议至少产生三次 dump信息,如果每次 dump都指向同一个问题,我们才确定问题的典型性。
  1. 获取PID
    jps 或 ps –ef | grep java
  2. 获取ThreadDump
    jstack [-l ] < pid > | tee -a jstack.log

ThreadDump信息:

1. "Timer-0" daemon prio=10 tid=0xac190c00 nid=0xaef in Object.wait() [0xae77d000]
2.  java.lang.Thread.State: TIMED_WAITING (on object monitor)
3.  at java.lang.Object.wait(Native Method)
4.  -waiting on <0xb3885f60> (a java.util.TaskQueue)     # 继续wait
5.  at java.util.TimerThread.mainLoop(Timer.java:509)
6.  -locked <0xb3885f60> (a java.util.TaskQueue)         # 已经locked
7.  at java.util.TimerThread.run(Timer.java:462)

第一行信息:

  • 线程名称:Timer-0;
  • 线程类型:daemon;
  • 优先级: 10,默认是5;
  • JVM线程id:tid=0xac190c00,JVM内部线程的唯一标识(通过java.lang.Thread.getId()获取,通常用自增方式实现)。
  • 对应系统线程id(NativeThread ID):nid=0xaef,和top命令查看的线程pid对应,不过一个是10进制,一个是16进制。(通过命令:top -H -p pid,可以查看该进程的所有线程信息)
  • 线程状态:in Object.wait();
  • 起始栈地址:[0xae77d000],对象的内存地址,通过JVM内存查看工具,能够看出线程是在哪儿个对象上等待;

第二行信息:
表示线程状态:TIMED_WAITING

2-7行的信息:
Java thread statck trace:到目前为止这是最重要的数据,Java stack trace提供了大部分信息来精确定位问题根源。堆栈信息应该逆向解读:程序先执行的是第7行,然后是第6行,依次类推。也就是说对象先上锁,锁住对象0xb3885f60,然后释放该对象锁,进入waiting状态

使用场景

  1. CPU飙高,load高,响应很慢
    一个请求过程中多次dump;
    对比多次dump文件的runnable线程,如果执行的方法有比较大变化,说明比较正常。如果在执行同一个方法,就有一些问题了;
  2. 查找占用CPU最多的线程
    使用命令:top -H -p pid(pid为被测系统的进程号),找到导致CPU高的线程ID,对应thread dump信息中线程的nid,只不过一个是十进制,一个是十六进制;
    在thread dump中,根据top命令查找的线程id,查找对应的线程堆栈信息;
  3. CPU使用率不高但是响应很慢
    进行dump,查看是否有很多thread struck在了i/o、数据库等地方,定位瓶颈原因;
  4. 请求无法响应
    多次dump,对比是否所有的runnable线程都一直在执行相同的方法,如果是的,恭喜你,锁住了!
  5. 死锁
    死锁经常表现为程序的停顿,或者不再响应用户的请求。从操作系统上观察,对应进程的CPU占用率为零,很快会从top或prstat的输出中消失。
    比如在下面这个示例中,是个较为典型的死锁情况:
"Thread-1" prio=5 tid=0x00acc490 nid=0xe50 waiting for monitor entry [0x02d3f000
..0x02d3fd68]
at deadlockthreads.TestThread.run(TestThread.java:31)
- waiting to lock <0x22c19f18> (a java.lang.Object)
- locked <0x22c19f20> (a java.lang.Object) "Thread-0" prio=5 tid=0x00accdb0 nid=0xdec waiting for monitor entry [0x02cff000
..0x02cff9e8]
at deadlockthreads.TestThread.run(TestThread.java:31)
- waiting to lock <0x22c19f20> (a java.lang.Object)
- locked <0x22c19f18> (a java.lang.Object)

附. 线程状态

  1. NEW 新建线程对象
    Thread t = new Thread();当刚刚在堆内存中创建Thread对象,还没有调用t.start()方法之前,线程就处在NEW状态。
    在这个状态上,线程与普通的java对象没有什么区别,就仅仅是一个堆内存中的对象。
  2. RUNNABLE 等待运行+正在运行
    表示线程在运行队列中等待CPU等资源的调度、或者正在运行。 这个状态的线程比较正常,但如果线程长时间停留在在这个状态就不正常了,这说明线程运行的时间很长(存在性能问题),或者是线程一直得不到执行的机会(存在线程饥饿的问题)。
  3. BLOCKED
    线程正在等待获取java对象的Minor(也叫内置锁),即线程正在等待进入由synchronized保护的方法或者代码块。
  4. WAITING
    处在该线程的状态,正在等待某个事件的发生,只有特定的条件满足,才能获得执行机会。而产生这个特定的事件,通常都是另一个线程。
    比如: A线程调用了obj对象的obj.wait()方法,如果没有线程调用obj.notify或obj.notifyAll,那么A线程就没有办法恢复运行;如果A线程调用了LockSupport.park(),没有别的线程调用LockSupport.unpark(A),那么A没有办法恢复运行。
  5. TIMED_WAITING
    如果线程进入了WAITING状态,一定要特定的事件发生才能恢复运行;而处在TIMED_WAITING的线程,如果特定的事件发生或者是时间流逝完毕,都会恢复运行。
  6. TERMINATED
    线程执行完毕,执行完run方法正常返回,或者抛出了运行时异常而结束,线程都会停留在这个状态。这个时候线程只剩下Thread对象了,没有什么用了。

Q:线程的 BLOCKEDWAITING 状态的区别?

  • 阻塞态:是指当一条正在执行的线程请求某一资源失败时,就会进入阻塞态。在Java中,阻塞态专指请求锁失败时进入的状态。由一个**同步队列(阻塞队列)**存放所有阻塞态的线程。处于阻塞态的线程会不断请求资源,一旦请求成功,就会进入就绪队列,等待执行。
  • 等待态:当前线程中调用wait、join、park函数时,当前线程就会进入等待态,只能等待其他线程的指示才能继续运行。进入等待态的线程会释放CPU执行权,并释放资源(比如锁)。也有一个等待队列存放所有等待态的线程。
  • 当前线程调用object.wait方法后,释放对象锁,这个状态就是WAITING状态,线程处于等待队列,等待其他线程同一个对象调用notify或者notifyAll方法。
    在调用notify或者notifyAll方法后,调用wait的等待线程不会立刻从等待队列返回,而是从等待队列移动到同步队列,准备竞争对象监视器的这种状态就是BLOCKED。

【JVM】常见调试排错场景、内存与线程Dump分析相关推荐

  1. 【JVM性能调优】jstack和线程dump分析

    一.几个概念: 1.jstack命令的语法格式:jstack <pid>,可用于查看java进程id. 2.Dump文件:Dump文件是进程的内存镜像.可以把程序的执行状态通过调试器保存到 ...

  2. 【jvm】jvm jstack使用 Java线程Dump分析

    1.概述 下面这个文章很好:调试排错 - Java线程Dump分析 常用jvm命令1 常用jvm命令1 常用jvm命令1

  3. Java线程dump分析及工具

    Java线程dump分析,可适用IBM的工具:IBM Thread and Monitor Dump Analyzer for Java 使用方法:java -jar jca*.jar.可加必要的VM ...

  4. jstack和线程dump分析

    一:jstack jstack命令的语法格式: jstack  <pid>.可以用jps查看java进程id.这里要注意的是:       1. 不同的 JAVA虚机的线程 DUMP的创建 ...

  5. 【JAVA】java性能分析之线程DUMP分析

    系统上线后,系统可能会出现一些迟钝.卡死现象,这个时候就需要我们对系统进行性能方面的优化.本文将大概介绍一下,性能问题的解决思路,以及一次应用系统操作缓慢的分析实操. 一.定位问题方向 首先,查看服务 ...

  6. Java线程Dump分析

    Thread Dump介绍 什么是Thread Dump Thread Dump是非常有用的诊断Java应用问题的工具.每一个Java虚拟机都有及时生成所有线程在某一点状态的thread-dump的能 ...

  7. Java线程Dump分析-工具TDA

    jstack用于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息,如果是在64位机器上,需要指定选项"-J-d64",Windows的jstack使 ...

  8. java dump 工具_Java线程Dump分析工具--jstack

    jstack用于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息,如果是在64位机器上,需要指定选项"-J-d64",Windows的jstack使 ...

  9. java线程dump_Java线程Dump分析 - PerfMa

    概览 分析概况主要统计了各个线程状态的线程数量.比例和后台守护线程的数量.比例. Top5数据,主要展示了线程,线程池,线程栈,方法,锁,5个维度的Top5的数据.点击查看全部,即可跳转到相应具体模块 ...

最新文章

  1. PMP知识要点(第七章)
  2. 网站服务器中病毒该如何处理,网站被中了木马无法删除怎么办? 解决网站中病毒的办法...
  3. Kewail-邮件短信接口的基础教程
  4. Pl/SQL Developer 配置
  5. 什么是服务网格(Service Mesh)
  6. MySQL表设计基础
  7. chattr和lsattr的基本用法
  8. 小小恋歌(小さな恋のうた)
  9. 爬虫实例5 爬取58房源信息(xpath)
  10. js与jQuery操作select大全
  11. Git 详解 和 廖雪峰 Git 教程
  12. 基于STM32CubeMX在STM32F072C8T6移植Contiki OS
  13. 百度搜索指数查询工具
  14. 联想thinkpad如何关闭触摸板
  15. Hammer.js 进行图片缩放
  16. Windows下编译语音识别引擎Wenet
  17. 【计算机网络】第四部分 网络层(21) 地址映射、差错报告和多播
  18. 树、二叉树(完全二叉树、满二叉树)概念图解
  19. 从QAM星座图判断噪声干扰
  20. 多个公网服务器搭建k8s集群

热门文章

  1. 学外语的忌讳-一个四十多岁的人是如何学英语的
  2. java decompiler插件_Java反編譯利器-Jad, Jode, Java Decompiler等及其IDE插件
  3. 李峋 同款代码,用html来进行表白
  4. 更省更快更安全的云服务器,一站式集中管理,随时随地远程——站斧云桌面
  5. 一道高数题的不等式解法
  6. 【ML】信息熵最值,不等式解法
  7. ValueError: Creating variables on a non-first call to a function decorated with tf.function.解决方法
  8. Javaweb(JSTL)—— ——Sun公司指定标准标签库
  9. 买新笔记本电脑,RJ45接口还香吗
  10. IDEA中输入sout回车后得到的是println如何解决