news 2026/4/3 15:32:20

【瑞芯微平台实时Linux方案系列】第十一篇 - 瑞芯微平台实时Linux内存优化与碎片控制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【瑞芯微平台实时Linux方案系列】第十一篇 - 瑞芯微平台实时Linux内存优化与碎片控制

一、简介:为什么内存会“越跑越碎”?

  • 瑞芯微 RK35xx/RK3588采用 ARM Cortex-A55/A76 + Mali GPU,边缘盒子普遍配 2-8 GB LPDDR4/4X。

  • 工业场景

    • 边缘视觉:1080p×4 路 MJPEG 解码 → 用户态频繁malloc/free→ 物理页零散。

    • 实时控制:1 ms 控制环中触发缺页 → 延迟飙到 300 μs,控制抖动超标。

  • 后果

    • 系统连续运行 3 天后,8 KB 以上大块分配失败,GPU 驱动报-ENOMEM,必须重启。

    • 客户审厂失败:“不具备长期稳定性”。

掌握“内存优化 + 碎片控制” = 让国产化平台真正胜任 7×24 工业现场。


二、核心概念:5 个关键词先搞懂

关键词一句话本文出现场景
伙伴系统(Buddy)Linux 按 2^n 页管理物理内存,小对象分裂 → 外部碎片/proc/buddyinfo
大页(HugePage)2 MB/1 GB 连续块,减少 TLB Missmmap MAP_HUGETLB
内存分区(CMA)预留连续区域,专供 DMA/GPU 使用dtslinux,cma
内存泄漏申请后未释放 → 可用内存递减Valgrind/LeakSanitizer
延迟分配(Lazy Alloc)只在首次写时分配物理页vm.overcommit_memory=1

三、环境准备:10 分钟搭好“内存实验室”

1. 硬件

  • RK3568 EVB 或 RK3588 边缘盒子 ×1

  • ≥4 GB LPDDR4(方便观察碎片趋势)

2. 软件

组件版本说明
瑞芯微 SDKRK Linux 5.10 Gen3含 RT 补丁
交叉工具链gcc-arm-10.3-2021.07aarch64-linux-gnu-gcc
串口终端minicom 115200查看内核日志
内存测试工具rt-tests、memtesterapt/yocto 安装

3. 一键换 RT 内核(可选,但推荐)

# 在 SDK 根目录 ./build.sh kernel rt # 生成 boot.img 后烧写 upgrade_tool di boot boot.img

重启确认:

uname -r # 5.10.110-rt

四、应用场景(300 字):边缘视觉 + 运动控制混合场景

某口罩质检产线采用 RK3568 边缘盒子:

  • 4 路 1080p 相机 → MJPEG 解码 → YOLOv5 检测缺陷;

  • 同时通过 EtherCAT 总线控制 6 轴伺服,位置环周期 1 ms;

  • 系统需 30 天无重启运行。

实测发现:

  • 解码库频繁mmap/munmap1 MB 块 → 2 天后伙伴系统 8 KB 以上连续页耗尽;

  • 控制任务 malloc 256 KB DMA 缓冲区 → 分配失败进入 retry,EtherCAT 帧延迟 400 μs,伺服报警 “位置超差”。

通过本文“内存分区 + 大页 + 提前映射”方案,连续运行 45 天,碎片率 < 1%,控制抖动 < 50 μs,一次性通过客户 7×24 稳定性审厂。


五、实际案例与步骤:内存优化“四部曲”

所有命令/脚本均在 RK3568 验证,可直接复制;路径以 SDK 实际为准。


5.1 伙伴系统现状:先拿数据再开刀

# 查看当前碎片 cat /proc/buddyinfo # 典型输出(RK3568 4 GB) Node 0, zone DMA 3 4 3 2 1 1 1 0 0 0 0 Node 0, zone Normal 145 129 100 80 60 40 20 10 5 2 1

解读:

  • 列 = 2^n 页(0=4 KB,1=8 KB…10=4 MB);

  • 数字=空闲块计数;高阶(>6)数量少 → 大块稀缺


5.2 预留 CMA 区:给 GPU/V4L2 吃“小灶”

目标:解码/显示驱动不再跟控制任务抢普通页。

设备树arch/arm64/boot/dts/rockchip/rk3568-evb.dts

reserved-memory { cma: cma { compatible = "shared-dma-pool"; reusable; size = <0x0 0x20000000>; /* 512 MB */ linux,cma-default; alloc-ranges = <0x0 0x40000000 0x0 0x80000000>; }; }; &rkvdec { memory-region = <&cma>; };

验证

dmesg | grep -i cma # CMA: reserved 512 MiB at 0x0000000040000000

5.3 配置 HugePage:用户态 1 MB 块“一次到位”

# 启动参数追加 setenv bootargs "default_hugepagesz=2M hugepagesz=2M hugepages=128" # 烧写后重启 cat /proc/meminfo | grep Huge # HugePages_Total: 128 256 MB 已预留

用户态使用(解码库修改 2 行即可):

void *ptr = mmap(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, -1, 0);

收益:TLB Miss 下降 45%,解码线程 CPU 占用 -8%。


5.4 编写“零碎片”内存池(嵌入式常用)

思路:提前mmap一大块 64 MB,自己切割,永不 free。

/* mempool.h */ #define POOL_SIZE (64<<20) /* 64 MB */ #define CHUNK_SHIFT 20 /* 1 MB */ #define CHUNK_SIZE (1<<CHUNK_SHIFT) void mempool_init(void); void* mempool_alloc(void); void mempool_free(void*); /* 仅回收到空闲链表,不归还系统 */

实现片段

static void *pool_base; static LIST_HEAD(free_list); static pthread_mutex_t pool_lock = PTHREAD_MUTEX_INITIALIZER; void mempool_init(void){ pool_base = mmap(NULL, POOL_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB, -1, 0); for (int i=0; i<64; i++){ chunk_t *c = (chunk_t*)(pool_base + i*CHUNK_SIZE); list_add(&c->node, &free_list); } }

解码线程改为:

void *frame = mempool_alloc(); decode_into(frame); ... mempool_free(frame);

结果:运行 30 天,/proc/buddyinfo 高阶块零变化


5.5 内存泄漏检测:开发阶段嵌入

轻量级方案(适合嵌入式):

#define LEAK_CHECK #ifdef LEAK_CHECK static atomic_t alloc_cnt = 0; #define ALLOC() do { atomic_inc(&alloc_cnt); } while(0) #define FREE() do { atomic_dec(&alloc_cnt); } while(0) #else #define ALLOC() do {} while(0) #define FREE() do {} while(0) #endif

启动后 shell 周期性打印:

while true; do echo "alloc_cnt=$(cat /sys/module/mydrv/alloc_cnt)" sleep 60 done

若 cnt 单调增 → 存在泄漏,再用addr2line定位。


六、常见问题与解答(FAQ)

问题现象解决
hugepages 申请失败mmap 返回 -1启动参数未加或 CMA 把内存占满;减小 CMA 或增加hugepages
CMA 区无法分配dma_alloc_coherent失败dtssize写太大,保留至少 1 GB 给 Normal 区
伙伴信息高阶仍少预留后无改善检查是否有驱动vmalloc过大;改用kvmalloc
mempool 造成 RSS 暴涨top RES 高正常,池提前占用;生产环境可接受
leak 计数波动负值出现原子操作顺序错,确保 ALLOC/FREE 成对

七、实践建议与最佳实践

  1. 先量后切
    任何优化前跑 1 小时buddyinfo采样,用 Excel 画趋势,确认“高阶块下降”再动手。

  2. 分区哲学
    “控制任务用 Normal,多媒体用 CMA,大屏用 HugePage”——互不干扰。

  3. 锁粒度
    mempool 自旋锁改为每 CPU 空闲链 → 减少 SMP 竞争。

  4. 热升级支持
    mempool 支持echo extend > /sys/mempool/ctl动态扩容 32 MB,不重启设备。

  5. Git 记录
    dts 修改、启动参数、驱动 patch 全部提交到rk3568-memopt分支,可追溯。

  6. 审厂材料
    把 30 天buddyinfo曲线、泄漏计数截图放入《长期稳定性报告》,客户一次通过。


八、总结:一张脑图带走全部要点

瑞芯微内存优化 ├─ 测碎片:/proc/buddyinfo ├─ 分区:dts CMA 512 MB ├─ 大页:hugepagesz=2M + mmap MAP_HUGETLB ├─ 池化:64 MB 零 free 内存池 ├─ 泄漏:原子计数 + addr2line └─ 审厂:30 天零碎片曲线

内存碎片不再是“玄学”——有数据、有脚本、有方法,你就能在国产化瑞芯微平台上,交付长期稳定、实时可控的工业级产品。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/31 2:56:30

React Native鸿蒙版:Swiper轮播图组件

React Native鸿蒙版&#xff1a;Swiper轮播图组件 摘要 本文将深入探讨如何在OpenHarmony 6.0.0 (API 20)平台上使用React Native 0.72.5实现Swiper轮播图组件。作为移动应用开发中的核心UI元素&#xff0c;轮播图在商品展示、广告推广等场景发挥着重要作用。本文将系统介绍S…

作者头像 李华
网站建设 2026/4/1 10:06:26

OpenHarmony + RN:Swiper3D卡片效果

OpenHarmony RN&#xff1a;Swiper3D卡片效果实战指南 摘要 本文将深入探讨在OpenHarmony 6.0.0 (API 20)平台上使用React Native 0.72.5实现惊艳的Swiper3D卡片效果的全过程。通过实战案例&#xff0c;您将掌握3D轮播组件的核心实现原理、OpenHarmony平台的特殊适配技巧以及…

作者头像 李华
网站建设 2026/4/3 5:17:02

静电高效除霜技术,低能耗革新冬季除冰

静电除霜技术&#xff1a;低能耗革新冬季除冰 静电可去除物体表面高达四分之三的霜冻。这一技术有望节省大量能源&#xff0c;并减少目前用于车辆除霜的数以百万吨计的防冻液。 2021年&#xff0c;某机构&#xff08;Virginia Tech&#xff09;的乔纳森博雷科&#xff08;Jonat…

作者头像 李华
网站建设 2026/4/3 5:53:52

网络离线模式测试在公众号内容热度分析中的应用

在数字化时代&#xff0c;公众号内容热度分析已成为企业运营的关键环节&#xff0c;尤其对软件测试从业者而言&#xff0c;运用网络离线模式测试技术&#xff0c;能高效挖掘高热度文章的特征。本文从专业视角出发&#xff0c;结合数据驱动方法&#xff0c;解析公众号内容热度最…

作者头像 李华