当前位置:   article > 正文

Linux下Java进程消耗内存异常高_linux中为什么jar包占用内存很大而且不释放

linux中为什么jar包占用内存很大而且不释放

遇到问题

  之前打的服务镜像被告知在集群上运行时占用了很多内存。

排查过程

  但我其实是很纳闷的,因为之前也在服务器上也做过测试,对内存的消耗很正常,大概只有500M上下,如今却被告知容器单启动后就使用了2G内存。
  先去证实一下,拿到了一台曾经被用作集群节点的服务器的使用权,把镜像传过去跑一下。

docker load -i XXX.tar
  • 1
docker run -it -m xxxM --cpus=x -e XXXX=xxxx -v XXXX=xxxx -p xxx:xxx XXX:x.x.x
  • 1

  简单看一下服务进程的资源使用情况

docker stats <containerId>
  • 1

或者

docker container top <containerId>
  • 1
top -p <pid>
  • 1

  此处没有图的,工作机截图不方便外传。发现RES [ resident memory usage ] 确实是2个G,很奇怪。
  通过-v的挂载路径把jar包取出来跑,其实在容器中运行的进程也是运行在服务器OS上的,但把jar包取出来部署方便使用其他工具监视。

java -XX:NativeMemoryTracking=detail -jar xxx.jar
  • 1

  先看一下资源占用

top -p <pid>
  • 1

  好吧,还是2G。
  看一下是什么东西占了这么多内存

jmap -histo <pid>
  • 1

  发现堆里最多的是char[]类型,大概有800M,纳闷了,看看是什么东西。
  做个堆快照

jmap -dump:format=b,file=xxx.hprof <pid>
  • 1

  分析一下,首先发现堆使用大小只有900M,奇怪了,那2G内存是哪用的?再看一下char[]都是些什么,实例数太多了,但随机抽着看发现都是些类加载的信息,应该可以被GC掉(确实可以被GC掉)。

  先看看详细的内存分配。可以用jcmd统计java heap申请的地址空间的和pmap的地址空间对比一下,可以看到操作系统统计的java heap实际使用的物理内存大小。

jcmd <pid> VM.native_memory detail
  • 1
pmap -x <pid>
  • 1

  按地址空间发现堆内存在pmap中被统计使用了1600M。
  和之前的堆快照对比一下,发现RES中统计堆内存使用的物理内存要明显高于实际使用的堆大小。

  做下GC。

jcmd <pid> GC.run
  • 1

  发现那些char[]只剩20M了,使用的堆内存也只有100M,但进程RES依然是2G,pmap中统计的堆内存使用的物理内存依然是1600M。
  也就是说,在GC之后,堆释放的内存并没有归还给操作系统。

  为什么没有归还给操作系统呢,是放入了内存分配器的内存池?还是commited部分的内存在使用后就会被操作系统一直统计?又或是其他原因

  临时解决方法:限制一下Xmx吧(起码看起来使用的内存明显少了)。

java -Xmx1280M -jar xxx.jar
  • 1

  但还有一些其他状况,我在分析pmap -x统计的内存使用情况时,发现有很多内存的地址不在jcmd统计的native memory中,起初以为是direct memory,后来了解到这是JNI调用的本地方法自行申请的内存。
  并且这些内存基本都是以64M大小划分的,查阅资料最后了解到了glibc的thread arena,glibc在2.11之后对每个线程引入了内存池。
  设置环境变量MALLOC_ARENA_MAX=1关掉thread arena机制,这些以64M划分的内存区域确实没了,但反而在别处多出来两块使用内存特别高的区域,还有别的内存池机制?
  服务启动时追踪一下系统调用,看看内存池是给哪些线程分配的。

strace -f -e"brk,mmap,munmap" -p <pid>
  • 1

  和jstack线程栈快照比对,追踪到了C1 Compiler Thread和C2 Compiler Thread头上,也确实开启了很多这样的线程,用JVM参数降低他们的数量。

java -Xmx1280M -XX:CICompilerCount=2 -jar xxx.jar
  • 1

  再用pmap -x查看,64M内存区域少了很多,进程RES也减了很多(起码看起来减了很多)。

结论

  内存分配器的内存池机制,导致操作系统会额外统计很多的内存使用,建议给Xmx设置一个合理值,glibc内存分配器的Thread Arena机制,也会占用很多内存。

疑惑

  • GC之后堆释放掉的内存去哪了
  • 关掉Thread Arena之后为何多出来两块实际使用内存很大的内存区域?是谁申请给谁用的?
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/616095
推荐阅读
相关标签
  

闽ICP备14008679号