Java高级特性之疑难问题定位-粗糙版

远程调试

server:

  • jdk1.4+: -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=*:5005 (jdk1.5之后,可以不用-Xdebug)
  • jdk1.5+:-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005
  • -Xrunjdwp/-agentlib:jdwp: 使用jdwp来运行调试环境
  • transport: 通信方式,dt_socket使用的是socket,dt_shmem使用的是共享内存,其中dt_shmem只适用于windows
  • server: 是否以作为调试服务端运行jvm
  • suspend: 程序启动后先暂停,等待客户端连接
  • address: 服务端监听的地址
  • onuncaught:当出现uncaught exception 后,是否中断jvm运行

client:

  • jdb -connect com.sun.jdi.SocketAttach:port=5005,hostname=localhost
  • stop, step, next, cont, locals, print, threads… , 可在jdk中通过help查看
  • 也可以通过eclipse,IDEA 远程调试功能连接

IDEA:

  • 打开 Run/Debug Configurations 窗口
  • 点击左上角加号 Add New Configuration
  • 选择 Remote JVM Debug

内存问题

运行时数据区:

  • 堆:新生代、老年代
  • 方法区:
  • 线程私有区:虚拟机栈、本地方法栈、程序计数器

常见问题:

  • “java.lang.OutOfMemoryError:Java heap space”: 堆内存不足。可能为内存泄漏、堆配置过小或配置不合理。可通过-Xms, -Xmx配置
  • java.lang.OutOfMemoryError: PermGen : JDK1.7以前,“space“: 永久代(方法区)空间不足。一般为加载类型过多引起。可通过-XX:PermSize和-XX:MaxPermSize配置,也可以查看是否使用-noclassgc 参数,JDK1.8之后为java.lang.OutOfMemoryError: Metaspace” 。
  • StackOverFlowError: 栈空间不足。一般为递归调用引起。通过-Xss配置
  • java.lang.OutOfMemoryError:可能为直接内存溢出。一般为通过NIO或JNI不断分配内存导致。通过-XX:MaxDirectMemorySize配置

注意:

  • 一般不要使用try-catch捕获OOM。

堆内存溢出:

  • 当出现java.lang.OutOfMemoryError: Java heap space异常,说明当前的堆内存不足,无法创建更多的Java对象

常见原因:

  • 堆内存太小,使用-Xmx 参数增加虚拟机最大堆内存的大小
  • Java代码内存泄漏导致的内存不足,属于代码的bug,mat等工具排查

定位方法:

  • jmap -histo 打印当前对象的个数和大小
  • jmap –histo:live 打印当前存活对象的个数和大小,
  • 此命令会触发一次full gc
  • jstat: -gc 查看gc情况
  • 过jmap -heap:format=b 获取内存信息
  • 在启动时增加-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=”具体的路 径”,当系统OutOfMemory之后,会将内存信息收集下来

堆内存泄漏:

  • 已经无用的对象仍然被其它对象引用就造成了内存泄漏

原因:

  • 全局变量(特别是容器类) 引用一个对象, 在不需要的使用没有释放。
  • 虽然正常情况对象进行了释放, 但是在异常情况下, 由于释放代码没有被执行到导致的缓慢内存泄漏
  • runnable类型的对象被new了, 但是没有按照正常的逻辑提交给线程去执行。 runnable这种特殊对象一旦new出来, 会被虚拟机自身所引用, 尽管用户代码中没有显式引用。

jdk图形工具:

  • jconsole: 可以查看堆内存和堆外内存分配情况
  • jvisualvm: 功能较jconsole多
  • mat:下载地址:https://www.eclipse.org/mat/
  • Shallow heap: 对象自身占用的内存,Retained heap:除了对象自身内存外,还包括对象引用其他对象引用的内存
  • 软引用:如果一个对象只有软引用,而当前堆空间不足,则GC会回收
  • 弱引用:不管内存是否足够,都会回收
  • 虚引用:是否有虚引用,都不影响对象的回收。好处是,能在被GC的时候收到通知
  • jmc: 配合jfr,不仅能够进行监控,还能够分析jvm的profiling和事件。其中jfr在jdk8u262和jdk11中可用,jmc下载地址http://jdk.java.net/jmc/

CPU使用率高

定位高CPU使用率的线程:

  • top –H –p PID: 查看java进程各线程CPU的使用情况

查看线程调用栈:

  • jstack PID: 查看高CPU使用率的线程在做什么

线程状态:

  • Blocking: 现在在等待锁(Lock或synchronized)
  • Waiting: 等待其他线程执行某些操作
  • Runnable: 就绪或运行状态
  • Timed_Waiting: 限时等待

其他原因:

  • 线程多,上下文切换次数多. 可通过vmstat查看
  • gc次数过多.可通过gc日志查看

死锁

jstack:

  • 命令:jstack pid
  • 线程占有一个锁:locked
  • 线程等待其它线程释放锁:waiting to lock
  • 线程占有一个锁,同时执行该锁的wait():

先打印 locked,然后打印— waiting on

GC

GC日志:

  • -XX:PrintGCTimeStamps:打印 GC 时间
  • -XX:PrintGCDetails :打印 GC 日志;
  • -Xloggc: path:保存GC 日志路径。
  • jstat –gcutil: 显示垃圾收集信息

常见问题:

  • 频繁gc: 堆空间不足
  • gc时间长:堆空间过大
  • 回收垃圾少:内存泄漏

Linux常用命令

  • vmstat:查看CPU上下文切换、中断次数
  • pidstat:查看进程CPU、内存、I/O指标
  • iostat:查看系统IO情况
  • mpstat:查看每个cpu的性能指标
  • strace: 查看进程的系统调用
  • free:查看系统内存使用情况
  • cachestat:查看整个系统缓存命中情况
  • cachetop: 查看每个进程命中缓存情况
  • sar:查看系统网络收发情况
  • tcpdump:抓取分析网络包