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:抓取分析网络包