解决docker容器(java程序)内存过大的问题

 更新时间:2025年07月23日 09:29:57   作者:L-960  
本文主要介绍了解决docker容器(java程序)内存占用过大的问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

1、系统层面内存排查

1 docker stats查看容器使用总内存

通过docker stats [容器id]命令查看内存占用如下:

CONTAINER ID   NAME  CPU %     MEM USAGE / LIMIT     MEM %     NET I/O          BLOCK I/O         PIDS
f414a2f20364   xxx   5.84%     38.19GiB / 123.2GiB   31.00%    1.34TB / 1.5TB   1.16GB / 29.8MB   354

2 在宿主机查看容器内存使用情况

1、通过ps -ef | grep [容器标识] 查询容器pid

root     12683     1  0 Feb11 ?        00:01:57 /usr/bin/containerd-shim-runc-v2 -namespace moby -id f414a2f203647ceab75bb4a1be3a1d0e5578eb14b9c1780810d6416c97bbdb86 -address /run/containerd/containerd.sock
  • 各列的解释:
    • UID(root): 用户ID,表示运行该进程的用户。在你的输出中,root表示该进程是由root用户启动的。
    • PID(12683): 进程ID,系统中每个进程的唯一标识符。
    • PPID(23606 和 1): 父进程ID,PPID为1,通常表示它是由init系统或Docker守护进程直接启动的。
    • C(0): CPU使用率的简化表示,通常是进程的调度优先级。
    • STIME(10:38 和 Feb11): 进程启动时间或日期。 10:38表示当天的时间,而Feb11表示进程是在2月11日启动的。
    • TTY( ?): 终端类型,表示进程关联的终端。pts/2表示伪终端,通常是用户通过SSH或终端会话启动的。?表示没有关联的终端,通常是后台进程。
    • TIME(00:00:00 和 00:01:57):进程使用的累计CPU时间。
    • CMD: 启动进程的命令及其参数。
  • containerd-shim介绍:
    • /usr/bin/containerd-shim-runc-v2:这是可执行文件的路径,表示containerd的一个组件,负责管理容器的生命周期。
    • -namespace moby:-namespace参数指定了容器所属的命名空间。在Docker中,moby通常是默认的命名空间,用于隔离不同的容器和资源。
    • -id f414a2f203647ceab75bb4a1be3a1d0e5578eb14b9c1780810d6416c97bbdb86:-id参数指定了容器的完整ID。这个ID是容器的唯一标识符,用于管理和操作容器。
    • -address /run/containerd/containerd.sock: -address参数指定了与containerd守护进程通信的Unix套接字地址。/run/containerd/containerd.sock是containerd的默认套接字文件,用于进程间通信。

2、通过父进程pid找到容器内进程的pid: ps -ef | grep f414a2f20364

root     12683     1  0 Feb11 ?        00:01:57 /usr/bin/containerd-shim-runc-v2 -namespace moby -id f414a2f203647ceab75bb4a1be3a1d0e5578eb14b9c1780810d6416c97bbdb86 -address /run/containerd/containerd.sock
root     12742 12683  3 Feb11 ?        22:02:41 java -jar xxx.jar

3、top -p [pid1,pid2]查看真正内存占用

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                                                                                               
12683 root      20   0  720048   8180   2888 S   0.0  0.0   1:57.85 containerd-shim                                                                                                                                       
12742 root      20   0   41.2g  27.9g   7008 S   0.0 22.6   1322:52 java 

3 内存显示不一致的问题

通过上述步骤,发现docker statstop所看到的内存不一致,原因如下:

docker stats显示的是整个容器的内存使用情况,包括所有进程的内存占用,还包括一些缓存和缓冲区的内存,这些在top中是不直接显示的。

4 排查容器的缓存占用

通过cgroup文件系统可以查看指定容器的内存使用情况:

  • cache:表示缓存的内存大小
  • rss:表示常驻内存大小。

1、方式1,在宿主机通过cgroup文件系统查看指定容器的内存使用情况。

cat /sys/fs/cgroup/memory/docker/容器id/memory.stat 

cache 20683264000
rss 29628477440
rss_huge 291504128
mapped_file 942080
swap 0
...

2、方式2,在容器内查看访问文件系统查看内存使用情况。

cat /sys/fs/cgroup/memory/memory.stat

cache 20683264000
rss 29629128704
rss_huge 291504128
mapped_file 1990656
swap 0
...

5 查看系统内存使用情况

无论在容器内外,使用cat /proc/meminfo命令,查看的都是当前宿主机的内存使用情况

cat /proc/meminfo

MemTotal:       129183640 kB
MemFree:          818860 kB
MemAvailable:   24080828 kB
Buffers:          180204 kB
Cached:         23378164 kB
SwapCached:            0 kB
Active:         113819220 kB
Inactive:       11582364 kB
Active(anon):   101853876 kB
Inactive(anon):    31492 kB
Active(file):   11965344 kB
Inactive(file): 11550872 kB
Unevictable:       10448 kB
...

2、jvm层面内存排查

1、查看堆内存情况

1、为docker赋予权限,使得容器内可以查看到宿主机的进程(不推荐,因为不安全)
docker run 添加--cap-add=SYS_PTRACE参数,或docker-compose添加如下参数:

version: "3"
services:
  xxx:
    image: xxx
    cap_add:
      - SYS_PTRACE

然后执行jmap -heap [pid],查看jvm使用情况

2、使用arthas查看(推荐)

curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar
[arthas@1]$ dashboard 

Memory                                         used            total           max            usage           GC                                                                                                           
heap                                           7276M           20714M          27305M         26.65%          gc.ps_scavenge.count                                   9623                                                  
ps_eden_space                                  1174M           4067M           10203M         11.51%          gc.ps_scavenge.time(ms)                                1112280                                               
ps_survivor_space                              8M              8M              8M             96.63%          gc.ps_marksweep.count                                  42                                                    
ps_old_gen                                     6093M           16638M          20479M         29.76%          gc.ps_marksweep.time(ms)                               49463                                                 
nonheap                                        340M            352M            -1             96.49%                                                                                                                       
code_cache                                     155M            159M            240M           64.72%                                                                                                                       
metaspace                                      166M            173M            -1             95.86%                                                                                                                       
compressed_class_space                         18M             19M             1024M          1.83%                                                                                                                        
direct                                         263K            263K            -              100.00%                                                                                                                      
mapped                                         0K              0K              -              0.00%                                                                                                                        

2、查看gc情况

root@f414a2f20364:/arthas# jstat -gcutil 1 1000
  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT   
 99.30   0.00   1.19  36.63  95.87  94.28   9625 1112.458    42   49.464 1161.923
 99.30   0.00   1.19  36.63  95.87  94.28   9625 1112.458    42   49.464 1161.923
 99.30   0.00   1.19  36.63  95.87  94.28   9625 1112.458    42   49.464 1161.923

3、查看jvm启动参数

添加--cap-add=SYS_PTRACE参数,执行如下命令:

root@f414a2f20364:/arthas#  jinfo 1

...
VM Flags:
Non-default VM flags: -XX:CICompilerCount=12 -XX:CMSFullGCsBeforeCompaction=3 -XX:CompressedClassSpaceSize=528482304 -XX:+HeapDumpOnOutOfMemoryError -XX:InitialHeapSize=2147483648 -XX:MaxHeapSize=8589934592 -XX:MaxMetaspaceSize=536870912 -XX:MaxNewSize=2863136768 -XX:MetaspaceSize=536870912 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=715653120 -XX:OldSize=1431830528 -XX:+UseCMSCompactAtFullCollection -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:+UseParallelGC 
Command line:  -Xms2g -Xmx8g -XX:MaxMetaspaceSize=512m -XX:MetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=3

4、查看直接内存的使用情况

Native Memory Tracker默认是关闭的,需要添加jvm启动参数查看:-XX:NativeMemoryTracking=summary

jcmd [pid] VM.native_memory summary
root@663104c83c9e:/app# jcmd 1 VM.native_memory summary
1:

Native Memory Tracking:

Total: reserved=10191931KB, committed=3140431KB
-                 Java Heap (reserved=8388608KB, committed=2621952KB)
                            (mmap: reserved=8388608KB, committed=2621952KB) 
 
-                     Class (reserved=1119589KB, committed=78181KB)
                            (classes #11966)
                            (malloc=15717KB #17876) 
                            (mmap: reserved=1103872KB, committed=62464KB) 
 
-                    Thread (reserved=71121KB, committed=71121KB)
                            (thread #70)
                            (stack: reserved=70820KB, committed=70820KB)
                            (malloc=231KB #414) 
                            (arena=69KB #126)
 
-                      Code (reserved=253980KB, committed=29992KB)
                            (malloc=4380KB #6007) 
                            (mmap: reserved=249600KB, committed=25612KB) 
 
-                        GC (reserved=322636KB, committed=303188KB)
                            (malloc=16156KB #296) 
                            (mmap: reserved=306480KB, committed=287032KB) 
 
-                  Compiler (reserved=205KB, committed=205KB)
                            (malloc=63KB #668) 
                            (arena=142KB #15)
 
-                  Internal (reserved=16497KB, committed=16497KB)
                            (malloc=16465KB #16598) 
                            (mmap: reserved=32KB, committed=32KB) 
 
-                    Symbol (reserved=16233KB, committed=16233KB)
                            (malloc=14211KB #139114) 
                            (arena=2022KB #1)
 
-    Native Memory Tracking (reserved=2845KB, committed=2845KB)
                            (malloc=12KB #140) 
                            (tracking overhead=2833KB)
 
-               Arena Chunk (reserved=217KB, committed=217KB)
                            (malloc=217KB) 

3 结论

1、jvm内存未限制
2、容器缓存占用较高
3、未限制容器内存上限

4 内存限制

1 限制jvm内存

配置jvm启动参数:

command: java -Xms2g -Xmx8g -XX:MaxMetaspaceSize=512m -XX:MetaspaceSize=512m -XX:NativeMemoryTracking=summary -XX:+HeapDumpOnOutOfMemoryError -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=3 -jar xxx.jar

以下是你提供的JVM参数的解释:

  • -Xms2g:设置JVM初始堆内存大小为2GB,这是JVM启动时分配的内存量。
  • -Xmx8g:设置JVM最大堆内存大小为8GB,这是JVM可以使用的最大内存量。
  • -XX:MaxMetaspaceSize=512m:设置元空间(Metaspace)的最大大小为512MB,元空间用于存储类元数据。
  • -XX:MetaspaceSize=512m: 设置元空间的初始大小为512MB,JVM会根据需要动态调整元空间的大小。
  • -XX:NativeMemoryTracking=summary:启用本地内存跟踪(Native Memory Tracking, NMT),并设置为摘要模式,NMT用于监控JVM的本地内存使用,帮助诊断内存泄漏和优化内存使用。
  • -XX:+HeapDumpOnOutOfMemoryError:启用此选项会在发生内存溢出错误时生成堆转储文件,便于后续分析和调试。
  • -XX:+UseCMSCompactAtFullCollection:在使用CMS(Concurrent Mark-Sweep)垃圾收集器时,启用在Full GC后进行内存压缩,以减少内存碎片。
  • -XX:CMSFullGCsBeforeCompaction=3: 设置在进行3次Full GC后进行一次内存压缩。这与UseCMSCompactAtFullCollection结合使用,帮助减少内存碎片。

2 清理宿主机cache

将所有未写的系统缓冲区写到磁盘中,包含已修改的i-node、已延迟的块I/O和读写映射文件,同时清除pagecache和slab分配器中的缓存对象。

sync; echo 3 > /proc/sys/vm/drop_caches

3 限制容器自身内存使用

version: "3"
services:
  xxx:
    deploy:
      resources:
        limits:
          memory: 10G

到此这篇关于解决docker容器(java程序)内存占用过大的问题的文章就介绍到这了,更多相关docker内存占用过大内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家! 

相关文章

  • 详解Docker Swarm概念与用法

    详解Docker Swarm概念与用法

    这篇文章主要介绍了Docker Swarm概念与用法,帮助大家更好的理解和使用docker容器,感兴趣的朋友可以了解下
    2020-09-09
  • Docker Buildx构建多平台镜像的实现

    Docker Buildx构建多平台镜像的实现

    本文主要介绍了Docker Buildx构建多平台镜像的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07
  • docker配置daemon.json镜像加速文件方式

    docker配置daemon.json镜像加速文件方式

    这篇文章主要介绍了docker配置daemon.json镜像加速文件方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-05-05
  • docker安装RocketMQ的实现(附填坑经验connect to failed)

    docker安装RocketMQ的实现(附填坑经验connect to failed)

    本文主要介绍了docker安装RocketMQ(附填坑经验connect to failed)
    2024-06-06
  • docker实现重新打tag并删除原tag的镜像

    docker实现重新打tag并删除原tag的镜像

    这篇文章主要介绍了docker实现重新打tag并删除原tag的镜像,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-11-11
  • 使用Golang玩转Docker API的实践

    使用Golang玩转Docker API的实践

    这篇文章主要介绍了使用Golang玩转Docker API的实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • Docker 搭建lamp应用实例详解

    Docker 搭建lamp应用实例详解

    这篇文章主要介绍了Docker 搭建lamp应用实例详解的相关资料,这里对搭建 LAMP的步骤做了详细介绍,需要的朋友可以参考下
    2016-11-11
  • Docker中部署mysql服务的方法及遇到的坑

    Docker中部署mysql服务的方法及遇到的坑

    这篇文章主要介绍了Docker中部署mysql服务的方法及遇到的坑,本文是小编细心给大家收藏整理下来的,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-11-11
  • docker安装jiacrontab可视化任务管理工具详解

    docker安装jiacrontab可视化任务管理工具详解

    jiacrontab 是基于 Web 的可视化定时任务管理工具,由 server(调度多 client)和 client(执行脚本)通过 RPC 通信构成,支持超时处理、并发控制、依赖管理及兼容 Linux crontab 格式,便于多服务器统一管理
    2025-07-07
  • Docker文件映射实现主机与容器间目录的双向映射

    Docker文件映射实现主机与容器间目录的双向映射

    本地文件系统和容器中的文件系统之间的交互是一项必不可少的功能,本文主要介绍了Docker文件映射实现主机与容器间目录的双向映射,具有一定的参考价值,感兴趣的可以了解一下
    2024-03-03

最新评论