文章目录
从容器的自动kill理解java程序的内存使用
一、操作系统的oom kill
引发操作系统对进程进行oom kill的原因:
1、当ram与swap耗尽,操作系统选择低优先级、耗用ram最多的进程进行kill
2、进程占用的ram超出cgroup的限制,如docker就是利用cgroup限制可用的系统资源
查看系统诊断日志,确认近期是否发生oom kill:
dmesg -T
二、java程序的oom
java程序的oom分为两类:
1、oom error
java自身对内存进行分区管理,任何一个区域的使用超出限制,都会引发oom error,并退出程序;老生代、metaspace、DirectMemory分别会由于占用太多的类实例、加载太多类定义、放太多缓冲数据而引发oom
2、oom kill
java进程使用的ram超过cgroup的限制或超过操作系统的可用ram,招来操作系统的oom kill
三、java的内存构成
为避免oom kill,需要了解java占用的内存构成,以设置合适的control group限制:
1、Heap
堆内存,放置未释放的类实例,新老生代共用,由-Xmx或-XX:MaxRAMPercentage设置最大值,默认值是1/4的当前ram或1/4的cgroup最大限制
2、Class
放置类定义,用-XX:MaxMetaspaceSize设置最大值,默认无限制
3、Thread
放置stack,即stackoverflow里的stack
4、Code
放置JIT字节码运行时编译成的机器码;如果使用Janino等在线编译工具,要释放类实例和classloader后,才能回收类定义和机器码占用的内存
5、GC
辅助运行GC逻辑需要使用的内存
6、DirectMemory
主要放置直接提供给操作系统的网络IO接口使用的缓冲数据,用-XX:MaxDirectMemorySize设置最大值,默认为heap最大值的85%
7、SHR
共享库/文件占用的内存;如:操作memory-mapped file来与操作系统的存储IO接口交互
要统计前5类构成,需在启动参数里加入-XX:NativeMemoryTracking=summary,查看命令:
jcmd <pid> VM.native_memory summary scale=MB
SHR,使用top命令直接查看
DirectMemory,使用RES - SHR - Native Memory 可得