分类 Troubleshooting 相关 下的文章

ZGC

Java 11开始, 引入了一个新的实验性质的垃圾收集器 Z Garbage Collector. 它能处理几 GB 到几 TB 的 heap, 保证 stop the world 的时间不超过10ms, 并且这个时间不随着 heap 的大小而增加.

官方主页: https://wiki.openjdk.java.net/display/zgc/Main

java debug JPDA (JavaTM Platform Debugger Architecture)

Java 是在 VM 里面运行的语言, 同时要做到平台无关性, 所以它有自己的 debug 接口和实现.
官方关于 JPDA 的链接: https://docs.oracle.com/javase/6/docs/technotes/guides/jpda/
jpda.png

上面的图很容易理解, VM 具体实现和 backend 接口直接使用 JVM TI 来作为通信接口.
Debugger 和 Debuggee 之间定义了协议: JDWP (这类似于 HTTP).
Debugger 自己的和后端通信以及自己的 UI 使用 JDI(这类似与 HTML)

如何远程 debug:
从 Java 9 开始:

java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=127.0.0.1:8000 myApp
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8000 myApp

Java 9 之前:

java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000 OurApplication

Java 5 之前:

java -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000 myApp

参数列表:
a list of options:

  1. transport is the only fully required option. It defines which transport mechanism to use. dt_shmem only works on Windows and if both processes run on the same machine while dt_socket is compatible with all platforms and allows the processes to run on different machines

  2. server is not a mandatory option. This flag, when on, defines the way it attaches to the debugger. It either exposes the process through the address defined in the address option. Otherwise, JDWP exposes a default one

  3. suspend defines whether the JVM should suspend and wait for a debugger to attach or not

  4. address is the option containing the address, generally a port, exposed by the debuggee. It can also represent an address translated as a string of characters (like javadebug if we use server=y without providing an address on Windows)

客户端最简陋的可以使用 jdk 自带 jdb.
更多信息参考: https://www.baeldung.com/java-application-remote-debugging

使用MAT 分析heap dump

  1. 下载及设置
    官方下载: https://www.eclipse.org/mat/
    JDK 最好用最新的 JDK, 因为最新的基本优化最多.
    根据你分析的 heap dump 的大小, 有时候需要调整 MAT 的 heap 的大小. 这个参数在 MAT 根目录的 MemoryAnalyzer.ini 文件里面. 我经常分析 30G 以下的 heap, 基本设置为 27G, 是 JVM 使用压缩指针来加速.
    sjc-sreop-001.png

    另外, 对于 HPROF 的 dump 来说, 我经常设置为非严格 parse, 因为有时候有点错误, 不影响分析:
    sjc-sreop-002.png

    文档: MAT 自带文档在 Help -> Help Contents 菜单里面, 或者在线版本的文档

  2. 分析
    正常情况下当你打开一个 heap dump 之后, 它会问你是否自动诊断内存泄漏, 如果你不是为了诊断内存泄漏, 可以取消这步.
    Histogram: 是按照类的实例数量聚集, 能很快发现包含大量实例的类. 一般情况下 char[] 或者 String 都在最上面, 这基本没有问题.
    Dominator Tree: 对于诊断内存泄漏非常有用, 如果能抓到一个对象 dominate 很多实例, 基本你找到了问题所在.
    OQL: 就像查询数据库的 SQL 语言, 非常方便的查找任何对象, 实例;
    Threads: 查看当前heap的所有线程, 对于发现某个对象是怎么被创建, 或引用的非常有帮助.

更多关于如何使用 OQL: Java heap dump OQL samples - where
------ 未完待续 -------

jmap & jhat

jmap 用来输出 JVM 的heap 相关信息, 或者生成 heap dump. 可以对一个正在运行的 JVM 进程使用这个命令, 也可以对一个 core dump. 它的功能基本都被 jcmd 命令所替代

jmap -histo <pid>  //jcmd <pid> help GC.class_histogram
jmap -histo:live <pid>   //jcmd <pid> help GC.class_histogram -all
jmap -clstats <pid>   //jcmd <pid> GC.class_stats
jmap -finalizerinfo <pid>  //jcmd <pid> GC.finalizer_info
jmap -dump:format=b,file=/tmp/heapdump.hprfo <pid>  //jcmd <pid> GC.heap_dump
jmap -dump:live,format=b,file=/tmp/heapdump.hprfo <pid>  //jcmd <pid> GC.heap_dump -all

jhat 对 heap dump 分析, 然后起一个本地 web 服务器, 开 7000 端口, 使用户可以在浏览器通过 OQL 查看 heap 里面的信息. 因为功能不够强大, 基本都用其他工具, 比如 MAT 或 Java VisualVM.

java.util.concurrent.ReentrantLock 与 synchronized 的对比

两者都可以实现同步, 在有些方面二者还是有很多区别. synchronized 是 java 的一个语法级别的特性, ReentrantLock 是 util 里面的一个辅助类.

相同点:

  1. 二者都可以实现锁;
  2. 二者都可以实现 生产者/消费者模式 wait/notify/notifyAll, await/signal/signalAll

不同点:

  1. synchronized 必须是一对 {} 中间的部分, 2 个 synchronized 的代码块无法交叉, ReentrantLock 的写法更灵活, 可以交叉;
  2. Lock 可以设置是否回应 interrupt;
  3. Lock 可以使用 tryLock() 如果不能获得锁, 立马返回;
  4. Lock 可以使用 tryLock(timeout) 可以设置尝试获得锁的最长等待时间;
  5. 一个 Lock 可以通过 newCondition 设置多个条件队列, 让他们等待不同的事件;
  6. ReentrantLock 可以设置是否是公平锁;
  7. synchronized 在 JDK 6 优化之后, 可以实现锁粗化, 偏向锁, 根据逃逸分析锁消除;