请教各位 linux/java 大佬们一个关于内存占用的问题。
先说下场景是一个 springboot + websocket-starter 的即时任务服务。单机 4c8g 只运行该服务,大概维持 2w+长连接。free -h 显示内存占用为 6.8G 。在 top 中显示该进程 RES 为 5.0G 。阿里云后台报警显示已经占用了 95%+的内存。
以下为 free -h 命令输出结果
[root@develop srv]# free -h
total used free shared buff/cache available
Mem: 7.4G 6.8G 223M 536K 321M 297M
Swap: 0B 0B 0B
以下为 top 命令按内存排序部分输出结果
top - 22:40:13 up 14 days, 5:36, 2 users, load average: 0.22, 0.18, 0.21
Tasks: 97 total, 1 running, 96 sleeping, 0 stopped, 0 zombie
%Cpu(s): 4.0 us, 1.2 sy, 0.0 ni, 94.5 id, 0.0 wa, 0.0 hi, 0.3 si, 0.0 st
MiB Mem : 7551.8 total, 220.8 free, 7008.6 used, 322.3 buff/cache
MiB Swap: 0.0 total, 0.0 free, 0.0 used. 295.5 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
22739 root 20 0 8646580 5.0g 14500 S 23.3 68.2 1485:21 java
1563 root 20 0 1005204 13264 2308 S 0.3 0.2 64:57.91 /usr/local/clou
859 root 20 0 574296 11484 188 S 0.0 0.1 1:33.52 tuned
380 root 20 0 47652 10988 10636 S 0.0 0.1 0:03.24 systemd-journal
我的疑问是这两个数据到底是怎么算的 [捂脸] ,为啥 free 显示占用 6.8G ,但是 top 里只看到 5.0G 的内存占用。
目前有点怀疑是否是内存泄露导致?还是因为 top 内统计不到堆外内存之类的?
求教大佬们解惑,谢谢!
1
XiaoxiaoPu 2021-01-22 23:24:03 +08:00
cat /proc/meminfo 看下。5.0G 只是那一个进程占用的内存,其他进程、内核、硬件都会使用内存的。
|
2
msg7086 2021-01-23 00:07:59 +08:00 via Android
套接字会用内核内存吧,虽然不知道用了多少。
话说既然跑 Java 了不如内存多给点,我们跑 Java 的小鸡给了 128G 内存基本不担心内存占用的问题。 |
3
nuk 2021-01-23 00:11:34 +08:00
还有 slab 呀,都不算在 RES 里面的
|
4
jaynos OP @XiaoxiaoPu @nuk 感谢,学到了新知识!根据 http://linuxperf.com/?p=142 这篇文章所说,我计算了下 meminfo 里的统计数据,还是有些会对不上,按文章所说,差的大概 1g 内存可能是因为 alloc_pages/__get_free_page 分配的?
@msg7086 根据 https://zhuanlan.zhihu.com/p/25241630 这篇文章,就算 1 个 tcp 连接占用 8k 内存,2w 个连接也不过 150M 左右 [捂脸] 我有点疑惑的是不知道堆外内存会不会被统计到 RES 中,因为从网上一些内存泄露的排查过程中有提到 zip 压缩的问题( https://www.cnblogs.com/aipaojiao/p/13680207.html ),而在实际项目中是有用到 websocket 的 permessage-deflate 扩展的( https://tools.ietf.org/html/rfc7692 ) ```plain // 去掉了为 0KB 的字段 MemTotal: 7733012 kB // 7551.78M MemFree: 215988 kB // 210.93M MemAvailable: 280524 kB // 273.95M Buffers: 28368 kB // 27.70M Cached: 225080 kB // 219.80M Active: 5467844 kB // 5339.60M Inactive: 111284 kB // 108.68M Active(anon): 5325980 kB // 5201.15M Inactive(anon): 236 kB // 0.23M Active(file): 141864 kB // 138.54M Inactive(file): 111048 kB // 108.45M Dirty: 440 kB // 0.43M AnonPages: 5325680 kB // 5200.86M Mapped: 46940 kB // 45.84M Shmem: 536 kB // 0.52M Slab: 143460 kB // 140.10M SReclaimable: 64056 kB // 62.55M SUnreclaim: 79404 kB // 77.54M KernelStack: 6816 kB // 6.66M PageTables: 15420 kB // 15.06M CommitLimit: 3866504 kB // 3775.88M Committed_AS: 5697572 kB // 5564.04M VmallocTotal: 34359738367 kB // 32768G VmallocUsed: 20152 kB // 19.68M VmallocChunk: 34359712252 kB // 32767.98G Percpu: 704 kB // 0.69M AnonHugePages: 4769792 kB // 4658M HugePages_Total: 0 HugePages_Free: 0 HugePages_Rsvd: 0 HugePages_Surp: 0 Hugepagesize: 2048 kB // 2M DirectMap4k: 66232 kB // 64.68M DirectMap2M: 3848192 kB // 3758M DirectMap1G: 4194304 kB // 4096M ``` |
5
kele1997 2021-01-23 11:42:51 +08:00
你应该再看看 1 楼说,你的 top 那个 5G 是 java 单个程序的占用的内存
top 显示占用的内存是 7008.6 MB, 而 free -h 看到了只有 6.8G ,这么看来两者相差 200MB 左右。。 根本就没有相差 1g 内存 ``` MiB Mem : 7551.8 total, 220.8 free, 7008.6 used, 322.3 buff/cache ``` |
6
XiaoxiaoPu 2021-01-23 12:48:44 +08:00
执行 slabtop 再看看呢?我猜测还是 socket 占用的内存,「就算 1 个 tcp 连接占用 8k 内存,2w 个连接也不过 150M 左右」这个只是粗略估计,每个连接占用的内存是动态的。假如网络数据很多,应用程序从 socket 读取数据之前、socket 把数据发给网卡之前,都要使用内存来暂存的。
|
7
jaynos OP @kele1997 #5 可能是我没表达清楚,我的想法是,这台机器只运行了一个 java 程序,在 top 里显示 RES 为 5g,但是 free 里显示已用 6.8g 。然后根据 1 楼所说我去查了相关资料,现学现卖发现还是会有 1g 的内存出入( slab 等加上 5g 之后)
在 free 和 top 里显示的差距应该部分缓存导致的,我想表达的是在 top 或者 free 里看到的内存占用与实际进程相加相差过大的问题 |
8
jaynos OP @XiaoxiaoPu #6 嗯哈,昨晚我也看到了 https@@@zhuanlan.zhihu.com/p/25241630 这篇文章里的讲解,结合我的实际情况(绝大多数是每隔 20s 的 ping/pong 心跳,服务端直接响应 pong,不做任何处理)考虑,我觉得 socket 应该不会暂存这么多的数据。昨晚升级了服务器,现场数据已经没了 [捂脸] ,不过今天看了下,大致是能对的上了。以下是 slabtop 的数据,看起来 socket 其实也没有那么大?
```plain Active / Total Objects (% used) : 381214 / 384110 (99.2%) Active / Total Slabs (% used) : 14068 / 14068 (100.0%) Active / Total Caches (% used) : 73 / 101 (72.3%) Active / Total Size (% used) : 136913.44K / 137986.20K (99.2%) Minimum / Average / Maximum Object : 0.01K / 0.36K / 8.00K OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME 75054 74990 99% 0.19K 3574 21 14296K dentry 46956 46956 100% 0.10K 1204 39 4816K buffer_head 32832 32553 99% 0.06K 513 64 2052K kmalloc-64 23472 23296 99% 0.66K 978 24 15648K proc_inode_cache 21808 21455 98% 0.25K 1363 16 5452K kmalloc-256 21392 21261 99% 0.07K 382 56 1528K avc_node 21024 20410 97% 0.12K 657 32 2628K kmalloc-128 19900 19713 99% 0.62K 796 25 12736K sock_inode_cache 19710 19513 99% 2.06K 1314 15 42048K TCPv6 16286 16286 100% 0.12K 479 34 1916K kernfs_node_cache 14283 14283 100% 0.58K 529 27 8464K inode_cache 11744 11744 100% 1.00K 734 16 11744K ext4_inode_cache 11424 11424 100% 0.04K 112 102 448K selinux_inode_security 5418 5418 100% 0.21K 301 18 1204K vm_area_struct 4864 4864 100% 0.02K 19 256 76K kmalloc-16 4096 4096 100% 0.01K 8 512 32K kmalloc-8 3500 3500 100% 0.57K 125 28 2000K radix_tree_node 3366 2613 77% 0.08K 66 51 264K anon_vma 3315 3315 100% 0.05K 39 85 156K shared_policy_node 3264 3264 100% 0.04K 32 102 128K ext4_extent_status 1792 1792 100% 0.03K 14 128 56K kmalloc-32 1785 1785 100% 0.19K 85 21 340K kmalloc-192 1722 1722 100% 0.09K 41 42 164K kmalloc-96 1584 1584 100% 1.00K 99 16 1584K kmalloc-1024 1184 1079 91% 0.50K 74 16 592K kmalloc-512 1080 1080 100% 0.11K 30 36 120K jbd2_journal_head 912 912 100% 0.66K 38 24 608K shmem_inode_cache 680 680 100% 0.02K 4 170 16K fsnotify_mark_connector 567 567 100% 0.19K 27 21 108K cred_jar 544 544 100% 0.12K 17 32 68K pid 540 540 100% 0.11K 15 36 60K task_delay_info ``` |
9
jaynos OP 其实从阿里云监控数据显示,内存占用是逐步上涨的,大概每 5 分钟上涨 0.01%(~0.7m ),所以我最初的调查方向都是以内存泄露为主 [捂脸]
|