背景
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进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




