暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

内存武器库

济南小老虎 2025-04-25
137

背景

CPU的算力是一切性能的基础.
但是内存是算力发挥的源泉. 
没有搞笑的内存/缓存结构. CPU的算力就会是一个无源之水
无本之木只能好看, 但是无法提供实际的价值.

所以内存是软件能够实现功能的基础和载体. 
内存性能的诊断和调优非常重要


内存基本工具

free -m 
可以看到内存的实际使用情况.
              total        used        free      shared  buff/cache   available
Mem:        1045810       31163      267383       73339      747263      915945
Swap:             0           0           0

Mem 表示物理内存
Swap 表示虚拟内存. 
虚拟内存大多数情况下可以关闭. 

Total 指代内存总量
Used  一般指代所有进程 commited 的内存. 
Free  指代没有任何进程在使用,并且随意可以给他进程使用的内存. 
Shared 只的是进程共享的内存总量. 一般情况下像是Oracle数据库 共享段会比较多一些.
Buffer/cache 一般cache 是 读缓存, buffer 是写入之前的缓冲. 
available    一般总内存出去实际used+shared 的内存就是可用内存. 


清理buff/cache

sync 
echo 3 >/proc/sys/vm/drop_caches
使用如上命令可以清理内存中的缓存和缓冲信息.
缓存一般都是可以立即进行清理的. 

需要说明 cache 一般是 进程最近从磁盘上读取的内存
本着程序的空间局限性和时间局限性,最近访问到的内存最容易再次被访问.
所以 清理他的时候可能会导致程序出现一定的性能滑坡.

dirty page 则是另外一种情况. sync 之后执行drop 会加快落盘. 
这样虽然会损失一部分性能, 但是保证了产品的准确性. 

drop_caches 的理解. 
 0:不释放(系统默认值)
 1:释放页缓存
 2:释放dentries和inodes
 3:释放所有缓存

其实 
1 释放的page caches 就会释放绝大部分内存
2 的时候释放的是 目录项目以及slab里面可能用不到的信息 
3 会释放1和2的全部, 所以理论上可以一次使用 3 释放尽可能多的资源.


pagcher

https://github.com/rfyiamcool/pgcacher/releases/tag/v0.3.3

可以下载编译好的二进制, 主要有x86 和 arm版本的

解压缩并且将文件放到 usr/bin 目录下面

tar -zxvf pgcacher_v0.3.3_Linux_x86_64.tar.gz
scp pgcacher usr/bin/

查看整个系统的cache占用情况

pgcacher -top -limit 10 
查看缓存占用最多的10个进程


效果为

Oracle启动之后的处理
+-------------------------------------------------------------+----------------+-------------+----------------+-------------+---------+
| Name                                                        | Size           │ Pages       │ Cached Size    │ Cached Pages│ Percent │
|-------------------------------------------------------------+----------------+-------------+----------------+-------------+---------|
| u01/app/oracle/product/12.2.0.1/db_1/bin/oracle            | 388.938M       | 99569       | 252.177M       | 64558       | 64.837  |
| u01/app/oracle/oradata/ora12c/system01.dbf                 | 940.008M       | 240642      | 232.914M       | 59626       | 24.778  |
| u01/app/oracle/oradata/ora12c/sysaux01.dbf                 | 980.008M       | 250882      | 120.086M       | 30742       | 12.254  |
| usr/bin/dockerd                                            | 77.257M        | 19778       | 58.675M        | 15021       | 75.948  |
| u01/app/oracle/product/12.2.0.1/db_1/lib/libclntsh.so.12.1 | 68.259M        | 17475       | 45.366M        | 11614       | 66.461  |
| usr/lib64/libLLVM-10.so                                    | 80.121M        | 20511       | 35.664M        | 9130        | 44.513  |
| u01/app/oracle/oradata/ora12c/redo06.log                   | 1.000G         | 262145      | 30.039M        | 7690        | 2.933   |
| usr/bin/containerd                                         | 28.168M        | 7211        | 22.199M        | 5683        | 78.810  |
| u01/app/oracle/product/12.2.0.1/db_1/lib/libhasgen12.so    | 30.013M        | 7684        | 21.264M        | 5444        | 70.849  |
| usr/lib64/dri/swrast_dri.so                                | 20.584M        | 5270        | 19.447M        | 4979        | 94.478  |
|-------------------------------------------------------------+----------------+-------------+----------------+-------------+---------|
│ Sum                                                         │ 3.552G         │ 931167      │ 837.831M       │ 214487      │ 23.034  │
+-------------------------------------------------------------+----------------+-------------+----------------+-------------+---------+


结论

我这边理解 linux 的 page caches 内存其实就与 JVM内部的堆区很类似. 
如果进程还存在, 那么可以通过 进程的/proc/$pid/fd 进行汇总查看对应的内存使用. 
如果进程已经不存在了, 那么page cache 内的理论上可以清除. 跟JVM里面的对象没有了与root对象的关联
可以使用gc进行进行回收. 
因为系统的GC频率较低. 所以内存压力可能一直显得保持的比较高. 

相对的 

但是因为程序的时间局部性和空间局部性: linux 认为保留最近使用的文件的page caches 是非常有用的. 
所以linux 其实除非是遇到了内存大量申请, 不然他是不会驱逐自己辛辛苦苦导入到内存里的缓存信息. 

[root@oracle12c oracle]# time scp filecopy301_9999.dump root/filecopy301_9999.dump
real    0m30.726s

[root@oracle12c oracle]# time scp filecopy301_9999.dump root/filecopy301_9999.dump2
real    0m28.721s

[root@oracle12c oracle]# time scp filecopy301_9999.dump root/filecopy301_9999.dump3
real    0m12.372s

[root@oracle12c oracle]# time scp filecopy301_9999.dump root/filecopy301_9999.dump4
real    0m28.558s

发现清除缓存之后 第一次的时间是最久的
当被复制的文件进行缓存之后, 后面几次的复制都会有所性能提升.


pmap

pmap 是实时查看 进程内存使用情况的命令
pmap 是一个在 Unix 和类 Unix 系统(如 Linux)中常用的命令行工具,
用于显示进程的内存映射。
它可以帮助用户查看一个进程使用了哪些共享库、堆、栈等内存区域,以及这些区域的大小和权限。
用法: pmap [选项] PID
-x:显示扩展的内存映射信息,包括权限、偏移量、设备号、文件大小、路径名等。
-X:显示更详细的内存映射信息,包括权限、偏移量、设备号、文件大小、文件名、地址空间大小等。
-d:显示内存映射的描述信息。
-q:简洁模式,不显示标题行。

之前讲究过 pmap 求解  堆区和堆外内存的区别. 
这里其实可以使用 pmap -X $pid 查看 innode 不为0 的 一般是加载jar包消耗的内存.
使用excel 可以简单计算, 一个大型产品, 加载jar包可能就需要 300MB左右的内存. 


pmap的简单计算

for i in `ps -ef |grep java |grep -v nacos |grep -v rtf |grep -v grep \
|awk '{print $2}'` ; do echo $i ;  echo -n "该进程的堆内存总数(KB): " ;\
pmap -x $i |sort -k3h |tail -n 2 |cut -c 17- |awk '{print $2}' |head -n 1  ;\
pmap -x $i |sort -k3h |tail -n 2 |cut -c 17- |awk '{print $2}'\
|awk 'NR==2{second=$1} NR==1{first=$1; next} END{print "该进程的堆外总内存(KB): " \
second-first}'
 ; echo -n "该进程全部内存总数(KB): " ; pmap -x $i |sort -k3h \
|tail -n 2 |cut -c 17- |awk '{print $2}' |tail -n 1  ;   done

16707
该进程的堆内存总数(KB): 14251400
该进程的堆外总内存(KB): 2894976
该进程全部内存总数(KB): 17146376


top

top 不仅可以发现CPU相关的也可以发现内存相关的.
比如在银行麒麟上面使用 top 然后输入 M 使用内存排序:
发现除了java主服务之后还有 audit和mate-indicator进程占用内存巨多
怀疑遇到了KylinV10的bug.
今天晚上与银河麒麟原厂沟通,客户很快就给予了反馈. 

被原厂工程师告知,是比较早的bug了:
https://www.kylinos.cn/support/update/6.html
https://www.kylinos.cn/support/update/11.html
然后解决方法也比较简单, 需要升级audit还有mate-indicator的组建就可以了.

然后自己又舔着脸问了下下载地址,告知了这个url
https://update.cs2c.com.cn/NS/V10/V10SP2/os/adv/lic/updates/aarch64/
https://update.cs2c.com.cn/NS/V10/V10SP2/os/adv/lic/base/aarch64/


工具协同验证

Pmap获取进程堆区信息. 
221903
该进程的堆内存总数(KB): 3416064
该进程的堆外总内存(KB): 3857864
该进程全部内存总数(KB): 7273928
223148
该进程的堆内存总数(KB): 4757920
该进程的堆外总内存(KB): 2152692
该进程全部内存总数(KB): 6910612
223151
该进程的堆内存总数(KB): 2355200
该进程的堆外总内存(KB): 2860300
该进程全部内存总数(KB): 5215500

使用pmap -X 加上shell语法分析 jar以及so内存使用情况: 
for i in `ps -ef |grep java |grep -v nacos |grep -v rtf |grep -v grep \
|awk '{print $2}'` ; doecho$i ;  echo -n "该进程的jar以及so占用内存情况(KB): " ;\
pmap -X $i |awk  '$5>0  {print $7}' |grep -v '=' | awk '{sum +=$1} END {print sum}' ;\
done

情况结果为: 
221903
该进程的jar以及so占用内存情况(KB): 128400
223148
该进程的jar以及so占用内存情况(KB): 108820
223151
该进程的jar以及so占用内存情况(KB): 108512


sar

sar -r 可以展示一下具体的结果过

09时30分00秒 kbmemfree   kbavail kbmemused  %memused kbbuffers  kbcached  kbcommit   %commit  kbactive   kbinact   kbdirty
09时40分01秒   4200148  68039976 193868136     97.88      1056 112103800 178450904     83.06  68886304 116481276       580
09时50分01秒   4212208  68024380 193856076     97.87      1056 112078544 178415740     83.04  68870600 116454920       848
10时00分01秒   4225424  68000476 193842860     97.87      1056 112039072 178396752     83.03  68867140 116425584       756
10时10分01秒   4460500  67706780 193607784     97.75      1056 111876336 178539168     83.10  68486504 116652648       552
10时20分01秒   4562728  68047328 193505556     97.70      1056 111754820 178439972     83.06  68415952 116594036       612
10时30分00秒   4424104  68003404 193644180     97.77      1056 111849300 178453836     83.06  68417536 116700348      1172
10时40分01秒   4415420  68026132 193652864     97.77      1056 111880296 178456604     83.06  68422912 116722820       472
10时50分01秒   4359472  67995576 193708812     97.80      1056 111918332 178439396     83.05  68415336 116762468       928

可以查看内存相关信息. 能够保留一个月的数据.
sar -r -f var/log/sa/sa01 比如查看本月第一天的数据. 


meminfo

cat proc/meminfo 
可以查看系统内存的详细信息: 
需要注意一下 pagetable. 可能比较重要.
上面是一些核心的统计信息.
cat proc/meminfo
MemTotal:       198068284 kB
MemFree:        159440716 kB
MemAvailable:   175970880 kB
Buffers:              12 kB
Cached:         26923876 kB
SwapCached:            0 kB
Active:         10539984 kB
Inactive:       25382040 kB
Active(anon):    4916016 kB
Inactive(anon): 13686892 kB
Active(file):    5623968 kB
Inactive(file): 11695148 kB
Unevictable:           0 kB
Mlocked:               0 kB
SwapTotal:             0 kB
SwapFree:              0 kB
Dirty:               312 kB
Writeback:             0 kB
AnonPages:       8998448 kB
Mapped:          4297932 kB
Shmem:           9790560 kB
KReclaimable:     948976 kB
Slab:            1340824 kB
SReclaimable:     948976 kB
SUnreclaim:       391848 kB
KernelStack:       43824 kB
PageTables:       462896 kB
NFS_Unstable:          0 kB


第二部分里面大页的内存比较重要, Oracle数据库需要开启大页.
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:    99034140 kB
Committed_AS:   71098100 kB
VmallocTotal:   34359738367 kB
VmallocUsed:           0 kB
VmallocChunk:          0 kB
Percpu:            38016 kB
HardwareCorrupted:     0 kB
AnonHugePages:         0 kB
ShmemHugePages:        0 kB
ShmemPmdMapped:        0 kB
FileHugePages:         0 kB
FilePmdMapped:         0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
Hugetlb:               0 kB
DirectMap4k:     2328448 kB
DirectMap2M:    181172224 kB
DirectMap1G:    19922944 kB


MALLOC_ARENA_MAX

for i in `ps -ef |grep java |grep caf |awk '{print $2}' ` ;\
doecho -n "该进程: $i 的ARENA数大概为: " ;  pmap -x $i \
 |awk '{print $2}' |grep ^6 \
 |grep -o '[[:digit:]]\{5\}' |wc -l ; \
done

查看分布情况
该进程: 187121 的ARENA数大概为: 125
该进程: 190445 的ARENA数大概为: 242
该进程: 190448 的ARENA数大概为: 229
该进程: 190455 的ARENA数大概为: 237
该进程: 190456 的ARENA数大概为: 235
该进程: 190459 的ARENA数大概为: 239
该进程: 190460 的ARENA数大概为: 223
该进程: 190461 的ARENA数大概为: 246
该进程: 190462 的ARENA数大概为: 243
该进程: 190464 的ARENA数大概为: 236
该进程: 190474 的ARENA数大概为: 224
该进程: 190486 的ARENA数大概为: 242


MALLOC_ARENA_MAX 的理解

glibc 从 2.11 左右开始的版本对多线程做了很多增强.
最大的增强是: 允许在多线程模式下可以开启多个ARENA
其中ARENA的含义 是连续的虚拟内存段地址范围. 
32位系统默认是1MB, 64位系统默认是 64MB.  

如果不设置参数的情况下: 
MALLOC_ARENA_MAX 的默认值是 CPU的Core数目*8
他这样的好处是, 多线程在分配内存时, 可以有更多的ARENA区域来使用
因为在ARENA内分配内存是需要加锁和解锁的. 
降低加锁解锁的过程能够极大的提升内存分配效率
这也就是为啥 栈内分配要比对内分配要快非常多的原因. 

虽然数量多的ARENA 可以提升内存分配效率.但是过多的_ARENA_也存在风险 
一方面会导致 进程的virt 存在过量的问题
另一方面是 如果 java对堆外内存的回收存在问题,会导致缓慢的内存泄露
导致因为堆外内存泄露引起的OOM宕机. 

建议不要设置的太大, 避免出现问题.


微服务的影响

glibc 其实做了很多优化
有部分blog 提示说: 
如果一次申请1kb的内存, 当前没有可用的ARENA并且还可以申请ARENA的话
那么glibc会给进程一个新的ARENA 的区域进行 内存分配. 

但是如果一次申请1MB的内存, 那么进程会直接将内存分配到Main的ARENA区域上面.
避免新开启一个ARENA导致的内存损耗. 

我这边发现微服务情况下的ARENA区域特别多. 
怀疑原因是 rpc通信时要快速形成很多线程进行交互
此时 每次申请的线程内存用量都很小, 所以glibc习惯性的给一个新的ARENA
导致ARENA的越来越多, 最终导致virt 内存非常多. 

可以通过top 能够看到
    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
 187121 root      20   0   28.3g  10.9g  12576 S  92.7   5.8 840:41.10 java
 190445 root      20   0   36.5g  10.1g  10100 S   3.6   5.4  61:09.85 java
 190486 root      20   0   28.0g   7.7g  12936 S  38.9   4.1 238:09.34 java
 190474 root      20   0   27.4g   7.0g   7984 S   2.0   3.7  57:22.88 java
 190455 root      20   0   27.6g   6.6g  13024 S   7.9   3.5  50:04.96 java
 190461 root      20   0   28.1g   6.3g  16412 S   3.3   3.3  62:53.61 java

会发现 virt 比 res 要高很多. 

bcc的学习

yum install -y bcc kernel-devel
yum install -y bcc-tools
yum -y install kernel-headers
export PATH=$PATH:/usr/share/bcc/tools

bcc 和 ebpf 这一块还需要完善

自己还未进行涉及.. 


bcc安装方法之二-前提条件之一

yum remove bpftrace
yum install cmake llvm -y 
dnf install -y bison cmake ethtool flex git iperf3 libstdc++-devel python3-netaddr python3-pip gcc gcc-c++ make zlib-devel elfutils-libelf-devel
dnf install -y clang clang-devel llvm llvm-devel llvm-static ncurses-devel
dnf -y install netperf
pip3 install pyroute2



安装 netperf
下载: http://www.netperf.org/netperf
也可以从这里下载: https://github.com/HewlettPackard/netperf/tags
最新版本是 2.7.0 

安装: 
tar 解压缩之后 进入目录 ./configure>make>make install 就可以安装
安装完后在当前目录的src目录下会出现 netperf 和 netserver 两个文件.就可以使用

安装livm 
cd /
git clone https://github.com/llvm/llvm-project.git
cd /llvm-project
mkdir -p build
cd build
cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_RTTI=ON -DLLVM_ENABLE_PROJECTS="clang;libcxx;libcxxabi" -G "Unix Makefiles" ../llvm 



bcc安装方法之二

cd /
git clone https://github.com/iovisor/bcc.git

cd /bcc
mkdir -p bcc-build
cd bcc-build/
cmake /bcc -DCMAKE_INSTALL_PREFIX=/usr -DENABLE_LLVM_SHARED=1
cd  /bcc
make -j10
make install 

未完结


文章转载自济南小老虎,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论