JVM异常处理
大约 5 分钟
top -p pid 看到某个进程占用的物理内存,以及创建的线程数,也可以通过Shift+f命令对指定列进行排序,从而找到异常线程的pid。然后可以通过jstack pid | grep 命令找到这个线程在做的事,从而进行排查。
ps axu | grep -E 'pid|USER' 通过这个方式也能看到某个进程占用的物理内存,结果和top命令是匹配的。
-Xms300m -Xmx300m 同时设置了这两个参数并不代表jvm一启动就会向os申请300m的内存(是指不会立即占用300m内存)。同理,-XX:MaxPermSize=300m -XX: PermSize=300m也是一样的,也不会立即占用300m内存。 具体当前jvm instance占用了多少内存(这里值堆内内存),可以通过jmap -heap pid查看。
jmap -heap pid 这个命令能查看当前jvm各个堆区域使用情况,把各个区域使用空间累加便得到当前jvm程序占用了多少内存。注意是堆内内存,这个命令是不能看到jvm对堆外内存的使用情况的。比如:
jmap -heap 3273
Attaching to process ID 3273, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 24.80-b11
using thread-local object allocation.
Parallel GC with 2 thread(s)
Heap Configuration:
MinHeapFreeRatio = 0
MaxHeapFreeRatio = 100
MaxHeapSize = 314572800 (300.0MB)
NewSize = 209715200 (200.0MB)
MaxNewSize = 209715200 (200.0MB)
OldSize = 5439488 (5.1875MB)
NewRatio = 2
SurvivorRatio = 8
PermSize = 104857600 (100.0MB)
MaxPermSize = 104857600 (100.0MB)
G1HeapRegionSize = 0 (0.0MB)
Heap Usage:
PS Young Generation
Eden Space:
capacity = 167772160 (160.0MB)
used = 165346688 (157.6868896484375MB)
free = 2425472 (2.3131103515625MB)
98.55430603027344% used
From Space:
capacity = 20971520 (20.0MB)
used = 0 (0.0MB)
free = 20971520 (20.0MB)
0.0% used
To Space:
capacity = 20971520 (20.0MB)
used = 0 (0.0MB)
free = 20971520 (20.0MB)
0.0% used
PS Old Generation
capacity = 104857600 (100.0MB)
used = 64028920 (61.06273651123047MB)
free = 40828680 (38.93726348876953MB)
61.06273651123047% used
PS Perm Generation
capacity = 104857600 (100.0MB)
used = 6504792 (6.203453063964844MB)
free = 98352808 (93.79654693603516MB)
6.203453063964844% used
3795 interned Strings occupying 301744 bytes.
也就是说如果想知道当前jvm使用的堆内内存,只需要简单的把Heap Usage模块的相关信息累加即可,都可以不关心各个区域的配置信息。
当然也可以通过jstat -gc pid 500ms 1000来实时查看堆中各个区域的使用情况。这个方式和上面那中方法结果是一致的。
- 查看jvm实例堆外内存的使用情况 很可惜我还没找到相关的工具可以直接查看这个信息的,但可以通过上面几个信息来得到堆外内存的使用情况。大致算法就是:堆内内存占用+堆外内存占用=总的jvm内存占用。 总的jvm内存占用:通过上面的1或2可以知道 堆内内存占用:jmap -heap pid 就可以计算出堆外内存占用情况。
2022/9/7补充: 应该可以开启 -XX:NativeMemoryTracking=detail 参数,然后通过 jcmd pid VM.native_memory detail | less 来查看
- 堆外内存使用异常 如果发现堆外内存使用异常,先检查是否开启了-XX:+DisableExplicitGC.(开启这个会影响到jvm对堆外内存的回收,所以在频繁使用了堆外内存的情况下,建议不要开启这个选项)。 如果没有开启,那一般就是程序光申请了却没有显式的释放。这个是否如果不清楚程序哪里使用了堆外内存,可以通过btrace脚本进行跟踪来获取调用堆栈,定位代码。 jdk提供用于堆外内存分配的api最底层的应该是Unsafe#allocateMemory方法,但这个方法是native,btrace对native方法的跟踪好像有点问题。所以可以试试拦截上一层的方法, 比如:java.nio.ByteBuffer#allocateDirect方法,示例如下: 至于如何使用btrace,入门可以参考:http://blog.csdn.net/wilsonpeng3/article/details/52576253 关于btrace的另外一些问题,就不再是本话题的讨论内容了。
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
import java.lang.reflect.Field;
@BTrace public class HelloBtrace {
@OnMethod(
clazz="java.nio.ByteBuffer",
method="allocateDirect"
)
public static void onF1() {
jstack();
println("Hello BTrace");
}
}
系统推荐
- ES6.2.3(3节点)数据迁移到ES7.4.1(5节点)
- NGINX
- CloudFlare 客户端证书的使用
- MySQL高可用
- Cornell Notes System
- 正则表达式匹配第几个符号问题
- MySQL索引
- 制作KVM ES镜像文件
- 简易版配置中心&初探原理
- SpringBoot服务在服务启动完成前被提前注册到nacos
- Mermaid示例
- 杂记
- 随机毒鸡汤:学习使我快乐,快乐是短暂的,不要去追求短暂的快乐。