解決docker容器(java程序)內存過大的問題
1、系統(tǒng)層面內存排查
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,系統(tǒng)中每個進程的唯一標識符。
- PPID(23606 和 1): 父進程ID,PPID為1,通常表示它是由init系統(tǒng)或Docker守護進程直接啟動的。
- C(0): CPU使用率的簡化表示,通常是進程的調度優(yōu)先級。
- STIME(10:38 和 Feb11): 進程啟動時間或日期。 10:38表示當天的時間,而Feb11表示進程是在2月11日啟動的。
- TTY( ?): 終端類型,表示進程關聯(lián)的終端。pts/2表示偽終端,通常是用戶通過SSH或終端會話啟動的。?表示沒有關聯(lián)的終端,通常是后臺進程。
- TIME(00:00:00 和 00:01:57):進程使用的累計CPU時間。
- CMD: 啟動進程的命令及其參數(shù)。
- containerd-shim介紹:
- /usr/bin/containerd-shim-runc-v2:這是可執(zhí)行文件的路徑,表示containerd的一個組件,負責管理容器的生命周期。
- -namespace moby:-namespace參數(shù)指定了容器所屬的命名空間。在Docker中,moby通常是默認的命名空間,用于隔離不同的容器和資源。
- -id f414a2f203647ceab75bb4a1be3a1d0e5578eb14b9c1780810d6416c97bbdb86:-id參數(shù)指定了容器的完整ID。這個ID是容器的唯一標識符,用于管理和操作容器。
- -address /run/containerd/containerd.sock: -address參數(shù)指定了與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 內存顯示不一致的問題
通過上述步驟,發(fā)現(xiàn)docker stats與top所看到的內存不一致,原因如下:
docker stats顯示的是整個容器的內存使用情況,包括所有進程的內存占用,還包括一些緩存和緩沖區(qū)的內存,這些在top中是不直接顯示的。
4 排查容器的緩存占用
通過cgroup文件系統(tǒng)可以查看指定容器的內存使用情況:
cache:表示緩存的內存大小rss:表示常駐內存大小。
1、方式1,在宿主機通過cgroup文件系統(tǒng)查看指定容器的內存使用情況。
cat /sys/fs/cgroup/memory/docker/容器id/memory.stat cache 20683264000 rss 29628477440 rss_huge 291504128 mapped_file 942080 swap 0 ...
2、方式2,在容器內查看訪問文件系統(tǒng)查看內存使用情況。
cat /sys/fs/cgroup/memory/memory.stat cache 20683264000 rss 29629128704 rss_huge 291504128 mapped_file 1990656 swap 0 ...
5 查看系統(tǒng)內存使用情況
無論在容器內外,使用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參數(shù),或docker-compose添加如下參數(shù):
version: "3"
services:
xxx:
image: xxx
cap_add:
- SYS_PTRACE
然后執(zhí)行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啟動參數(shù)
添加--cap-add=SYS_PTRACE參數(shù),執(zhí)行如下命令:
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啟動參數(shù)查看:-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啟動參數(shù):
command: java -Xms2g -Xmx8g -XX:MaxMetaspaceSize=512m -XX:MetaspaceSize=512m -XX:NativeMemoryTracking=summary -XX:+HeapDumpOnOutOfMemoryError -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=3 -jar xxx.jar
以下是你提供的JVM參數(shù)的解釋:
- -Xms2g:設置JVM初始堆內存大小為2GB,這是JVM啟動時分配的內存量。
- -Xmx8g:設置JVM最大堆內存大小為8GB,這是JVM可以使用的最大內存量。
- -XX:MaxMetaspaceSize=512m:設置元空間(Metaspace)的最大大小為512MB,元空間用于存儲類元數(shù)據(jù)。
- -XX:MetaspaceSize=512m: 設置元空間的初始大小為512MB,JVM會根據(jù)需要動態(tài)調整元空間的大小。
- -XX:NativeMemoryTracking=summary:啟用本地內存跟蹤(Native Memory Tracking, NMT),并設置為摘要模式,NMT用于監(jiān)控JVM的本地內存使用,幫助診斷內存泄漏和優(yōu)化內存使用。
- -XX:+HeapDumpOnOutOfMemoryError:啟用此選項會在發(fā)生內存溢出錯誤時生成堆轉儲文件,便于后續(xù)分析和調試。
- -XX:+UseCMSCompactAtFullCollection:在使用CMS(Concurrent Mark-Sweep)垃圾收集器時,啟用在Full GC后進行內存壓縮,以減少內存碎片。
- -XX:CMSFullGCsBeforeCompaction=3: 設置在進行3次Full GC后進行一次內存壓縮。這與
UseCMSCompactAtFullCollection結合使用,幫助減少內存碎片。
2 清理宿主機cache
將所有未寫的系統(tǒng)緩沖區(qū)寫到磁盤中,包含已修改的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內存占用過大內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
docker安裝RocketMQ的實現(xiàn)(附填坑經驗connect to failed)
本文主要介紹了docker安裝RocketMQ(附填坑經驗connect to failed)2024-06-06
docker實現(xiàn)重新打tag并刪除原tag的鏡像
這篇文章主要介紹了docker實現(xiàn)重新打tag并刪除原tag的鏡像,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11
Docker文件映射實現(xiàn)主機與容器間目錄的雙向映射
本地文件系統(tǒng)和容器中的文件系統(tǒng)之間的交互是一項必不可少的功能,本文主要介紹了Docker文件映射實現(xiàn)主機與容器間目錄的雙向映射,具有一定的參考價值,感興趣的可以了解一下2024-03-03

