哪些进程或容器占用了多少 Page Cache

目录标题

    • 🧠 一、分析内存占用的几个核心指标
    • 🛠️ 二、使用 `smem` 查看每个进程内存详情
      • 📦 安装(适用于所有 Linux)
      • 📊 查看内存详情
      • 示例输出字段说明:
    • 📐 三、手动查看某进程的 Page Cache 占用
      • 示例:
    • 🐳 四、Kubernetes 容器层面分析:用 cgroup memory.stat
      • 1️⃣ 找到容器对应的 cgroup 路径:
      • 2️⃣ 查看 `memory.stat`
      • 重点字段说明:
    • 📦 五、快速脚本:列出每个容器的 page cache 占用(crictl 版本)
    • 🔄 六、推荐工具:`cgroups-metrics-exporter` 或 Prometheus
    • ✅ 总结

在容器化的 Linux 系统中(如 Kubernetes Node 上)看到内存占用高但 free 显示还有很多 buff/cache,想进一步精细化分析 哪些进程或容器占用了多少 Page Cache,可以使用如下方法:


🧠 一、分析内存占用的几个核心指标

指标含义
RSSResident Set Size,进程实际占用物理内存(不含 cache)
PSSProportional Set Size,按共享页比例分摊后的物理内存
USSUnique Set Size,仅该进程独占的内存
Page Cache文件映射缓存,可能会被共享,用于缓存磁盘文件

🛠️ 二、使用 smem 查看每个进程内存详情

📦 安装(适用于所有 Linux)

sudo apt install smem   # Debian/Ubuntu
sudo yum install smem   # CentOS/RHEL

📊 查看内存详情

smem -r -k -t -P ""     # 显示所有进程,包含 PSS 和缓存使用

示例输出字段说明:

 PID User     Command     USS      PSS      RSS     Swap
1234 root     java     100MB    500MB    800MB     0KB
  • PSS 比 RSS 更真实地反映进程实际内存压力
  • 若进程缓存占比很高,可以说明 page cache 占用明显

📐 三、手动查看某进程的 Page Cache 占用

grep -i '^file' /proc/<pid>/smaps_rollup

示例:

grep -i '^file' /proc/1234/smaps_rollup

输出类似:

FilePss:                32184 kB
FileRss:                32600 kB

说明该进程当前 page cache 占用了约 32MB。


🐳 四、Kubernetes 容器层面分析:用 cgroup memory.stat

容器的 memory usage 统计在 cgroup 下的 /sys/fs/cgroup 路径中:

1️⃣ 找到容器对应的 cgroup 路径:

docker inspect <container_id> | grep -i cgroup

或者 Kubernetes:

crictl inspect <container_id> | grep cgroup

常见路径:

/sys/fs/cgroup/memory/kubepods.slice/kubepods-besteffort-podXXXXXX.slice/docker-<id>.scope/memory.stat

2️⃣ 查看 memory.stat

cat /sys/fs/cgroup/memory/.../memory.stat

重点字段说明:

字段含义
cachepage cache 使用量(KB)
rss匿名内存(程序运行的真实内存)
mapped_file映射的文件大小
pgfault/pgmajfault缺页异常次数
inactive_file, active_file具体 cache 使用情况

示例:

cache 26214400       # 约 25MB 被该容器用于缓存
rss 524288000        # 匿名内存约 500MB

📦 五、快速脚本:列出每个容器的 page cache 占用(crictl 版本)

#!/bin/bash
echo -e "ContainerID\t\tCache(KB)\tRSS(KB)"
for cid in $(crictl ps -q); do
  cgroup_path=$(find /sys/fs/cgroup -name "*$cid*" 2>/dev/null | grep memory | head -n1)
  if [[ -f "$cgroup_path/memory.stat" ]]; then
    cache=$(grep '^cache ' $cgroup_path/memory.stat | awk '{print $2}')
    rss=$(grep '^rss ' $cgroup_path/memory.stat | awk '{print $2}')
    echo -e "$cid\t$cache\t\t$rss"
  fi
done

🔄 六、推荐工具:cgroups-metrics-exporter 或 Prometheus

如果你想持续监控,可以使用:

  • cadvisor(自动暴露容器级 memory.cache)
  • cgroups-metrics-exporter(专门导出 memory.stat 指标)
  • Prometheus + node_exporter(开启 textfile_collector 自定义指标)

✅ 总结

方法优点场景
smem + smaps_rollup精细分析进程级 cache排查单个进程内存高问题
memory.stat精确看容器级 page cacheKubernetes 排查容器内存
Prometheus exporter自动化、长期监控大规模集群、持续告警
drop_caches释放 page cache临时紧急处理,不建议频繁

### Java 缓存机制概述 Java 中的缓存机制旨在通过存储计算结果其他昂贵资源的结果来优化应用程序性能。这减少了重复执行相同操作的需求,从而提高了效率并降低了延迟。 #### Guava Cache 实现本地缓存 Guava 是 Google 提供的一套 Java 工具包,其中包含了功能强大的本地缓存组件——Guava Cache[^1]。这种缓存方案适用于 JVM 内部的数据暂存需求: ```java import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; public class GuavaCacheExample { private final LoadingCache<String, String> cache = CacheBuilder.newBuilder() .maximumSize(100) // 设置最大条目数 .expireAfterWrite(10, TimeUnit.MINUTES) // 设置写入后过期时间 .build(new CacheLoader<String, String>() { @Override public String load(String key) throws Exception { return fetchValueFromDatabase(key); } }); private String fetchValueFromDatabase(String key) { // 模拟从数据库获取数据的过程 return "value_for_" + key; } public String getValue(String key) { try { return cache.getUnchecked(key); } catch (Exception e) { throw new RuntimeException(e); } } } ``` 此代码片段展示了如何利用 `CacheBuilder` 创建带有自动加载能力的缓存实例,并设置了大小限制以及过期策略。 #### 使用 Map 手动构建简易缓存 虽然直接基于 `ConcurrentHashMap` 构建简单的键值对映射可以快速实现基本的缓存逻辑[^2],但在生产环境中通常不建议这样做,因为缺乏更高级别的特性支持,比如容量控制、淘汰算法等。 ```java import java.util.concurrent.ConcurrentHashMap; import java.util.UUID; public class SimpleLocalCache { public static ConcurrentHashMap<String, String> cache = new ConcurrentHashMap<>(); static { String value = "item-" + UUID.randomUUID().toString(); cache.put("key", value); System.out.println("Item with ID 'key' has been added to the cache."); } public void clearCache() { synchronized (cache) { cache.clear(); } } } ``` 上述例子中定义了一个静态成员变量作为全局共享的缓存容器,在类初始化时向其插入一条测试记录,并提供了清除整个缓存的方法[^3]。 #### 关于传统 HashMap 方式的局限性 采用普通的 `HashMap` 者其他基础集合类型来自行设计缓存结构存在诸多不足之处[^4]: - **内存泄漏风险**:如果不对缓存项设置合理的生命周期管理,则可能导致大量无用对象占用宝贵的空间; - **缺少持久化手段**:一旦进程终止重启,所有已缓存的信息都将消失不见; - **并发处理不当**:多线程环境下读取/更新同一份数据可能会引发竞态条件等问题; - **跨节点同步困难**:对于分布式部署的应用而言,不同机器上的独立缓存难以保持一致状态。 #### 多层次缓存体系架构 现代企业级应用往往依赖多层次组合的方式来满足复杂的业务场景下的高效能要求[^5]。具体来说就是将操作系统层面、中间件层面上的各种缓存技术结合起来运用: - **操作系统 Disk Cache**:用于加速磁盘 I/O 访问频率较高的文件内容; - **数据库 Buffer Pool**:针对 SQL 查询语句所返回的结果集做临时性的驻留缓冲区; - **ORM Framework Object Caching**:像 Hibernate 这样的 ORM 映射工具自带的对象级别缓存能够有效减少与底层 RDBMS 的交互次数; - **Application Level Query/Page Caching**:在 Web 层面实施页面级别的整体输出结果者特定部分 HTML 片段的高速回放机制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值