vault backup: 2024-05-25 19:26:16

This commit is contained in:
baim0
2024-05-25 19:26:16 +08:00
parent 6b522b72c9
commit 17cd5d0bb3
2 changed files with 9 additions and 471 deletions
+6 -5
View File
@@ -13,7 +13,7 @@
"state": {
"type": "markdown",
"state": {
"file": "k8sFunny/未命名.md",
"file": "k8sFunny/06 Linux 内存分析与观测.md",
"mode": "source",
"source": false
}
@@ -85,7 +85,7 @@
"state": {
"type": "backlink",
"state": {
"file": "k8sFunny/未命名.md",
"file": "k8sFunny/06 Linux 内存分析与观测.md",
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical",
@@ -102,7 +102,7 @@
"state": {
"type": "outgoing-link",
"state": {
"file": "k8sFunny/未命名.md",
"file": "k8sFunny/06 Linux 内存分析与观测.md",
"linksCollapsed": false,
"unlinkedCollapsed": true
}
@@ -125,7 +125,7 @@
"state": {
"type": "outline",
"state": {
"file": "k8sFunny/未命名.md"
"file": "k8sFunny/06 Linux 内存分析与观测.md"
}
}
}
@@ -149,8 +149,9 @@
},
"active": "abf2c3acea123adf",
"lastOpenFiles": [
"k8sFunny/07 coredns 常见问题.md",
"k8sFunny/06 Linux 内存分析与观测.md",
"prometheus/04 服务发现.md",
"k8sFunny/未命名.md",
"terrafrom",
"prometheus/03 查询.md",
"prometheus/01 基本概念.md",
@@ -1,6 +1,4 @@
# Linux 内存分析与观测
## 一、Linux 内存的观测
## Linux 内存的观测
### 1. 系统内存
@@ -102,11 +100,10 @@ $ vmstat 2
|PSS|Proportional Set Size|比例集大小,与RSS类似,唯⼀的区别是在计算共享库内存是是按⽐例分配。⽐如某个共享库占用了3M内存,同时被3个进程共享,那么在计算这3个进程的PSS时,该共享库这会贡献1兆内存。PSS通过考虑共享内存的比例,对共享内存进行分配,从而更准确地反映了进程占用的实际物理内存。|
|USS|Unique Set Size|唯一集大小,代表进程独占的物理内存大小,不包含Swap和共享库。也就是说,如果有多个进程共享同一块内存,这部分内存只会计入一个进程的USS。|
![进程内存的关系](./images/进程内存的关系.jpg)
以上这些指标可以通过`/proc/[pid]/smaps`文件中找到,其中pid是进程的ID。这四者的⼤⼩关系是:VSS >= RSS >= PSS >= USS
分析进程内存的整体使⽤情况,可以从 `/proc/[pid]/status` 文件中读取信息,显示的内容包括进程的VSS和RSS,下面是相关字段的含义:
```shell
# 系统中 kubelet进程为例
$ cat /proc/377598/status
@@ -555,7 +552,6 @@ nginx-ingress-controller-75c587dfd5-vwmpz 4m 121Mi
```
需要注意的是 Metrics-Server 并不是 kube-apiserver 的一部分,而是通过 Aggregator 这种插件机制,在独立部署的情况下同 kube-apiserver 一起统一对外服务的。
当 Kubernetes 的 API Server 开启了 Aggregator 模式之后,再访问 `/apis/metrics.k8s.io/v1beta1` 的时候,实际上访问到的是一个叫作 kube-aggregator 的代理。而 kube-apiserver,正是这个代理的一个后端, Metrics-Server 则是另一个后端。
通过上面的接口访问Metrics-Server服务,最后会获取到由 cAdvisor 提供的 cgroup数据,这里对应的内存指标名为 container_memory_working_set_bytes。其代表的含义是容器真实使用的内存量,也是资源限制limit时的重启判断依据,超过limit会导致oom。
@@ -654,467 +650,8 @@ container_memory_usage_bytes指标可以直接从 cgroup 中的 memory.usage_in_
}
```
## 二、案例分析
### 1. 低版本内核系统中容器内存 total_active_file 数量级高
- 问题描述
- 某集群中的Pod,监控显示 Pod内存使用为 5.5G,但是 Pod中服务本身只使用了1.6G
- 重点排查步骤
- kubernetes 官方文档也说明了 kubelet 将 active_file 内存区域视为不可回收
- [active_file 内存未被视为可用内存](https://kubernetes.io/zh-cn/docs/concepts/scheduling-eviction/node-pressure-eviction/#active-file-%E5%86%85%E5%AD%98%E6%9C%AA%E8%A2%AB%E8%A7%86%E4%B8%BA%E5%8F%AF%E7%94%A8%E5%86%85%E5%AD%98)
```shell
# 节点系统 centos_7_06_64_20G_alibase_20190619.vhd 3.10.0-957.21.3.el7.x86_64
# /sys/fs/cgroup/memory/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod<pod ID>.slice/
$ cat /sys/fs/cgroup/memory/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod9c785710_32ec_4baa_a967_3183025768fa.slice/memory.stat
cache 0
rss 0
rss_huge 0
mapped_file 0
swap 0
pgpgin 0
pgpgout 0
pgfault 0
pgmajfault 0
inactive_anon 0
active_anon 0
inactive_file 0
active_file 0
unevictable 0
hierarchical_memory_limit 3221225472
hierarchical_memsw_limit 9223372036854771712
total_cache 1928810496
total_rss 1292386304
total_rss_huge 14680064
total_mapped_file 32768
total_swap 0
total_pgpgin 4825542
total_pgpgout 4042694
total_pgfault 3627216
total_pgmajfault 262
total_inactive_anon 0
total_active_anon 1292386304
total_inactive_file 580984832
total_active_file 1347825664 # 数量级很高
total_unevictable 0
# 集群中每个node节点上容器的total_active_file缓存,占用都有20-30G
$ cat /sys/fs/cgroup/memory/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod*.slice/memory.stat |grep total_active_file |awk '{a+=$2}END{print a}'
35410173952
# 高内核版本的系统 ALinux2 4.19.91-27.7.al7.x86_64 内核
$ cat /sys/fs/cgroup/memory/kubepods/burstable/poda3726f29-0381-11ee-a39b-5254001450b7/memory.stat
cache 0
rss 0
rss_huge 0
shmem 0
mapped_file 0
dirty 0
writeback 0
swap 0
pgpgin 0
pgpgout 0
pgfault 0
pgmajfault 0
inactive_anon 0
active_anon 0
inactive_file 0
active_file 0
unevictable 0
hierarchical_memory_limit 4294967296
hierarchical_memsw_limit 9223372036854771712
total_cache 1852940288
total_rss 2250285056
total_rss_huge 0
total_shmem 0
total_mapped_file 401408
total_dirty 520192
total_writeback 0
total_swap 0
total_pgpgin 53762041
total_pgpgout 52760277
total_pgfault 11727726
total_pgmajfault 18
total_inactive_anon 0
total_active_anon 2250285056
total_inactive_file 1812811776
total_active_file 40095744 # 明显下降
total_unevictable 0
```
- 验证测试
- 清理缓存 `echo 1 > /proc/sys/vm/drop_caches`,有效
- 升级node节点的系统内核小版本,进行验证,没有效果
```shell
# 升级内核版本
# 1、确定当前内核版本
$ uname -r
3.10.0-514.26.2.el7.x86_64 # 需要升级到 kernel-3.10.0-1160.45.1.el7.x86_64.rpm 版本(用于安装GPU驱动)
# 2、下载指定内核版本
# 下载地址:http://ftp.scientificlinux.org/linux/scientific/7.0/x86_64/updates/security/
$ wget http://ftp.scientificlinux.org/linux/scientific/7.0/x86_64/updates/security/kernel-3.10.0-1160.45.1.el7.x86_64.rpm
# 3、安装内核版本
# 直接使用yum安装下载到本地的内核版本
$ yum -y install kernel-3.10.0-1160.45.1.el7.x86_64.rpm # 安装过程中没有报错,表示安装成功
# 4、列出当前系统所有内核版本
$ awk -F\' '$1=="menuentry " {print i++ " : " $2}' $(find /boot -name grub.cfg)
# 5、列出系统引导入口
$ grub2-editenv list
# 6、修改默认引导入口
$ grub2-set-default 0
# 7、重新构建一下grub菜单配置文件
$ grub2-mkconfig -o /boot/grub2/grub.cfg
# 验证 total_active_file 正常
$ cat memory.stat |grep total_active_file
total_active_file 61095936 # 61095936/1024/1024/1024 = 0.056GB
```
- 临时方案
- 先执行 `sync` ,用于将文件系统的缓冲区数据立即写入磁盘,以确保数据的持久性。
- 然后再执行下面的命令
- 清除pagecache `echo 1 > /proc/sys/vm/drop_caches`
- 回收slab分配器 `echo 2 > /proc/sys/vm/drop_caches`
- 执行 `sync` 会把内存数据落盘;回收slab分配器会释放页缓存,回收期间会对系统性能产生一些影响,但影响不大
- 最终方案
- 集群新增使用高内核版本系统的节点
- 服务迁移,逐渐替换老节点
### 2. java容器内存过大
- 问题描述
- 某生产集群中的Java Pod,监控显示 Jvm只使用了 1.3G,但是Pod内存监控却有 4.88G
- 信息收集
```shell
$ kubectl -n app-ns get pod app-java-86348df32-rs8ne -oyaml
apiVersion: v1
kind: Pod
metadata:
name: app-86348df32-rs8ne
namespace: app-ns
spec:
containers:
- env:
- name: JAVA_OPTS
value: java -jar -XX:+UseContainerSupport -XX:InitialRAMPercentage=70.0 -XX:MaxRAMPercentage=70.0
-Dspring.profiles.active=prod -XX:-UseAdaptiveSizePolicy -XX:NewRatio=2 -XX:SurvivorRatio=8 app.jar
- name: K8S_ENV
value: prod
- name: k8s_logs_console
value: stdout
- name: k8s_logs_console_tags
value: topic=k8s-app_java-console-log
image: hub/app-java:0.0.2-v9926675b
imagePullPolicy: Always
lifecycle:
preStop:
exec:
command:
- /bin/sh
- -c
- echo stop > /tmp/prestop;wget http://127.0.0.1:54199/offline 2>/tmp/null;sleep
30;exit 0
livenessProbe:
failureThreshold: 10
httpGet:
path: /app-java/keepalive
port: http
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
name: app-java
ports:
- containerPort: 11192
name: http
protocol: TCP
readinessProbe:
failureThreshold: 10
httpGet:
path: /app-java/keepalive
port: http
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
resources:
limits:
cpu: 2048m
memory: 6Gi
requests:
cpu: 200m
memory: 2Gi
...
$ kubectl -n app-ns top pod app-java-86348df32-rs8ne
NAME CPU(cores) MEMORY(bytes)
app-java-86348df32-rs8ne 229m 5006Mi
# 以下为java容器内的执行结果
$ cat /sys/fs/cgroup/memory/memory.stat
cache 1146900480
rss 5227409408
rss_huge 1799356416
shmem 0
mapped_file 3784704
dirty 0
writeback 0
swap 0
workingset_refault_anon 0
workingset_refault_file 67313664
workingset_activate_anon 0
workingset_activate_file 36360192
workingset_restore_anon 0
workingset_restore_file 0
workingset_nodereclaim 0
pgpgin 11128953
pgpgout 10215508
pgfault 89880285
pgmajfault 66
inactive_anon 5226868736
active_anon 0
inactive_file 1128783872
active_file 18247680
unevictable 0
hierarchical_memory_limit 6442450944
hierarchical_memsw_limit 6442450944
total_cache 1146900480
total_rss 5227409408
total_rss_huge 1799356416
total_shmem 0
total_mapped_file 3784704
total_dirty 0
total_writeback 0
total_swap 0
total_workingset_refault_anon 0
total_workingset_refault_file 67313664
total_workingset_activate_anon 0
total_workingset_activate_file 36360192
total_workingset_restore_anon 0
total_workingset_restore_file 0
total_workingset_nodereclaim 0
total_pgpgin 11128953
total_pgpgout 10215508
total_pgfault 89880285
total_pgmajfault 66
total_inactive_anon 5226868736
total_active_anon 0
total_inactive_file 1128783872
total_active_file 18247680
total_unevictable 0
$ ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 Aug08 ? 00:00:00 /pause
root 64 0 0 Aug08 ? 00:00:00 /bin/sh -c ${JAVA_OPTS}
root 69 64 23 Aug08 ? 19:31:54 java -jar -XX:+UseContainerSupport -XX:InitialRAMPercentage=70.0 -XX:MaxRAMPercentage=70.0 -Dspring.profiles.active=prod -XX:-UseAdaptiveSizePolicy -XX:NewRatio=2
root 145074 0 0 Aug11 pts/0 00:00:00 /bin/sh -c TERM=xterm-256color; export TERM; LANG=C.UTF-8; export LANG; [ -x /bin/bash ] && ([ -x /usr/bin/script ] && /usr/bin/script -q -c "/bin/bash" /dev/null
root 145079 145074 0 Aug11 pts/0 00:00:00 /bin/sh -c TERM=xterm-256color; export TERM; LANG=C.UTF-8; export LANG; [ -x /bin/bash ] && ([ -x /usr/bin/script ] && /usr/bin/script -q -c "/bin/bash" /dev/null
root 145080 145079 0 Aug11 pts/0 00:00:00 /usr/bin/script -q -c /bin/bash /dev/null
root 145081 145080 0 Aug11 pts/1 00:00:00 sh -c /bin/bash
root 145082 145081 0 Aug11 pts/1 00:00:00 /bin/bash
root 145251 145082 0 Aug11 pts/1 00:00:17 top
root 189604 0 0 11:03 pts/2 00:00:00 /bin/sh -c TERM=xterm-256color; export TERM; [ -x /bin/bash ] && ([ -x /usr/bin/script ] && /usr/bin/script -q -c "/bin/bash" /dev/null || exec /bin/bash) || exec
root 189609 189604 0 11:03 pts/2 00:00:00 /bin/sh -c TERM=xterm-256color; export TERM; [ -x /bin/bash ] && ([ -x /usr/bin/script ] && /usr/bin/script -q -c "/bin/bash" /dev/null || exec /bin/bash) || exec
root 189610 189609 0 11:03 pts/2 00:00:00 /usr/bin/script -q -c /bin/bash /dev/null
root 189611 189610 0 11:03 pts/3 00:00:00 sh -c /bin/bash
root 189612 189611 0 11:03 pts/3 00:00:00 /bin/bash
root 189696 0 0 11:05 pts/4 00:00:00 /bin/sh -c TERM=xterm-256color; export TERM; [ -x /bin/bash ] && ([ -x /usr/bin/script ] && /usr/bin/script -q -c "/bin/bash" /dev/null || exec /bin/bash) || exec
root 189701 189696 0 11:05 pts/4 00:00:00 /bin/sh -c TERM=xterm-256color; export TERM; [ -x /bin/bash ] && ([ -x /usr/bin/script ] && /usr/bin/script -q -c "/bin/bash" /dev/null || exec /bin/bash) || exec
root 189702 189701 0 11:05 pts/4 00:00:00 /usr/bin/script -q -c /bin/bash /dev/null
root 189703 189702 0 11:05 pts/5 00:00:00 sh -c /bin/bash
root 189704 189703 0 11:05 pts/5 00:00:00 /bin/bash
root 189831 189704 0 11:08 pts/5 00:00:00 ps -ef
$ cat /proc/69/status
Name: java
Umask: 0022
State: S (sleeping)
Tgid: 69
Ngid: 0
Pid: 69
PPid: 64
TracerPid: 0
Uid: 0 0 0 0
Gid: 0 0 0 0
FDSize: 1024
Groups:
NStgid: 69
NSpid: 69
NSpgid: 64
NSsid: 64
VmPeak: 21901288 kB
VmSize: 21835752 kB
VmLck: 0 kB
VmPin: 0 kB
VmHWM: 5127832 kB
VmRSS: 5120108 kB
RssAnon: 5095276 kB
RssFile: 24832 kB
RssShmem: 0 kB
VmData: 5758564 kB
VmStk: 168 kB
VmExe: 4 kB
VmLib: 17776 kB
VmPTE: 11688 kB
VmSwap: 0 kB
HugetlbPages: 0 kB
CoreDumping: 0
THP_enabled: 1
Threads: 225
SigQ: 0/506295
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000000000
SigCgt: 2000000191005cdf
CapInh: 00000000a80425fb
CapPrm: 00000000a80425fb
CapEff: 00000000a80425fb
CapBnd: 00000000a80425fb
CapAmb: 0000000000000000
NoNewPrivs: 0
Seccomp: 0
Speculation_Store_Bypass: vulnerable
Cpus_allowed: ffffffff
Cpus_allowed_list: 0-31
Mems_allowed: 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000001
Mems_allowed_list: 0
voluntary_ctxt_switches: 5
nonvoluntary_ctxt_switches: 5
```
![Java容器内存](./images/Java容器内存.jpg)
- 数据分析
```
从之前收集的信息看:
1、Java容器内存
container_memory_usage_bytes = container_memory_rss + container_memory_cache + kernel memory(kernel可以忽略)
container_memory_working_set_bytes = container_memory_usage_bytes - total_inactive_file(未激活的匿名缓存页)
= container_memory_rss + container_memory_cache + kernel memory(kernel可以忽略) - total_inactive_file
= 5227409408 + 1146900480 - 1128783872
= 5245526061/1024/1024/1024
= 4.885 GB
其中 container_memory_cache - total_inactive_file(未激活的匿名缓存页)= 1146900480 - 1128783872
total_inactive_file 本身就包含在cache里面,所以这里的4.88GB中,包含的cache可以忽略不计了
2、Java信息
Jvm堆栈内存为 1.3GB
Java启动参数为
java -jar -XX:+UseContainerSupport -XX:InitialRAMPercentage=70.0 -XX:MaxRAMPercentage=70.0
-Dspring.profiles.active=prod -XX:-UseAdaptiveSizePolicy -XX:NewRatio=2 -XX:SurvivorRatio=8 app.jar
3、Java进程信息
pod中 cat /proc/69/status 这个java进程的信息
Name: java
VmRSS: 5120108 kB/1024 = 5000mB /1024 = 4.88gB
4、服务pod资源限制为
resources:
limits:
cpu: 2048m
memory: 6Gi
requests:
cpu: 200m
memory: 2Gi
```
![容器内java进程rss过大](./images/内存使用高2.jpg)
- 最终结论
- 根据计算得出,Java容器内存为 4.885GB,cache可以忽略不计
- Java容器内java进程,VmRSS 为 4.88gB,说明该java进程的内存使用量基本占用了,Java容器全部的已使用内存
- 而此时jvm只有1.3GB,需要根据代码分析,其余内存是如何消耗的,是否有泄漏现象
### 3. java容器进程占用问题
#### 问题描述
- 场景一
- 用户容器内的java进程,使用了约 5.3g的内存
- 但是从Java的应用监控看,堆内存4454M,非堆内存426M
- 这两个加起来还差 5.3g-4.8g=0.5g 左右
- 下图,是通过 `jstat -class {pid}` 拿的数据
- 场景二
- 场景一的pod,第二天凌晨出现了 fullgc,Java的jvm堆栈监控显示内存下降 2G左右,但是容器中的java进程内存消耗还是约 5.3g
- 即 Java进程实际使用的物理内存,没有释放。查看内核问题,实际也是这样。
- `jmap`
- 使用`jmap -heap pid`输出堆内存中的对象信息,包括产生了哪些对象,对象数量多少等。
- 查看堆内存初始化配置信息以及堆内存的使用情况
- 使用`jmap -histo[:live] pid`查看堆内存中的对象数目、大小统计直方图,如果带上 live 则只统计活对象
- 排查过程
- 可以使用 pmap 命令
- 关于 pmap 命令的介绍,可以参考这个文档 [pmap,linux工具pmap原理?](https://www.cnblogs.com/Chary/p/16719738.html)
- 下面是基于 `pmap -x 1` 命令,打印的容器 java主进程的内存消耗
- 可以看到rss总数是可以对上的,而第一个内存地址 00000006a0000000 有 4502168,即 4.29GB,看起来就是jvm的占用
```shell
➜ pmap -x 1
1: java -jar -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/logs/${HOSTNAME}-dump.log -XX:NewRatio=2 -XX:InitialRAMPercentage=75.0 -XX:MinRAMPercentage=75.0 -XX:MaxRAMPercentage=75.0 -Xss512K -XX:+UseConcMarkSweepGC -Dspring.profiles.active=pro -Darthas.telnetPort=3659 -Darthas.httpPort=8564 -Darthas.agent-id=sch-inventory-start demp-xxxxx.jar
Address Kbytes RSS Dirty Mode Mapping
00000006a0000000 4750420 4502168 4502168 rw--- [ anon ]
00000007c1f15000 1016748 0 0 ----- [ anon ]
0000561e5793b000 4 4 0 r-x-- java
0000561e57b3b000 4 4 4 r---- java
0000561e57b3c000 4 4 4 rw--- java
0000561e58949000 4156 4136 4136 rw--- [ anon ]
00007fb12b6a2000 12 0 0 ----- [ anon ]
00007fb12b6a5000 504 24 24 rw--- [ anon ]
00007fb12b723000 12 0 0 ----- [ anon ]
00007fb12b726000 504 28 28 rw--- [ anon ]
00007fb12b7a4000 12 0 0 ----- [ anon ]
00007fb12b7a7000 504 28 28 rw--- [ anon ]
00007fb12b825000 12 0 0 ----- [ anon ]
...
00007fb2731bd000 4 4 4 rw--- libpthread-2.31.so
00007fb2731be000 24 12 12 rw--- [ anon ]
00007fb2731c4000 4 4 0 r---- LC_MEASUREMENT
00007fb2731c5000 4 4 0 r---- LC_IDENTIFICATION
00007fb2731c6000 4 4 4 rw--- [ anon ]
00007fb2731c7000 4 4 0 r---- ld-2.31.so
00007fb2731c8000 128 128 0 r-x-- ld-2.31.so
00007fb2731e8000 32 32 0 r---- ld-2.31.so
00007fb2731f0000 4 0 0 r---- [ anon ]
00007fb2731f1000 4 4 4 r---- ld-2.31.so
00007fb2731f2000 4 4 4 rw--- ld-2.31.so
00007fb2731f3000 4 4 4 rw--- [ anon ]
00007fff0ca3d000 144 48 48 rw--- [ stack ]
00007fff0ca66000 12 0 0 r---- [ anon ]
00007fff0ca69000 8 4 0 r-x-- [ anon ]
ffffffffff600000 4 0 0 r-x-- [ anon ]
---------------- ------- ------- -------
total kB 11135288 5517748 5499792%
```
#### 问题结论
- 场景一
- Java进程除了 Jvm内存(包括堆内存 Heap、堆外内存 Non-Heap),还有非Jvm内存,包括本地运行库、JNI本地代码
- 参考文档 [JVM监控内存详情说明](https://help.aliyun.com/zh/arms/application-monitoring/developer-reference/jvm-monitoring-memory-details)
- 场景二
- Java的jvm堆栈监控看到fullgc后内存降下来,但是Java进程实际上并没有释放,这个是因为jvm申请的堆内存会回收,但是并不会归还给操作系统,从操作系统角度看内存是不会下降的
- jvm在回收了堆中的内存之后,并不会立刻将这部分内存归还给操作系统
- 相反,它会保留这些内存以备将来再次使用,这样做可以减少因为频繁地向操作系统申请和释放内存而带来的性能开销
- 业务侧动作
- 将JVM堆的 limit占比从75%改为60%
- 从代码层面去减少对象的创建和长时间内存占用,减少长时间执行的代码和长时间的引用
- 其他排查文件
- [持续剖析功能](https://help.aliyun.com/zh/arms/application-monitoring/user-guide/enable-continuous-profiling)
- [慢调用链诊断利器-ARMS 代码热点](https://mp.weixin.qq.com/s/_fzVzCX4bts7RByanU_Feg)
## 三. 参考文档
## 参考文档
- [关于Linux性能调优之内存负载调优](https://blog.51cto.com/liruilong/5930543)
- [Linux中进程内存RSS与cgroup内存的RSS统计 - 差异](https://developer.aliyun.com/article/54407)