当前位置: 首页 > news >正文

Linux 查询目录下文件大小引发的内存溢出问题

在 Linux 系统中执行命令:

du -sh /data/* > xx.txt

并观察到 top 中有一个 bash 进程的 VIRT(虚拟内存)RES(常驻内存) 显著增长,这种现象看似反常,因为通常 du 命令本身才是主要消耗资源的进程,而不是 bash。下面从命令执行逻辑和内存增长原因两方面进行分析。


一、命令执行逻辑分析

1. Shell 展开通配符 /data/*

当你在终端输入:

du -sh /data/* > xx.txt

bash 首先会进行通配符(glob)展开,即把 /data/* 替换为 /data/ 目录下所有文件和子目录的实际路径列表。例如:

du -sh /data/file1 /data/file2 /data/dir1 /data/dir2 ... > xx.txt

这个展开过程完全由 bash shell 本身完成,在 fork/exec du 之前。

2. 参数列表长度可能非常大

如果 /data/ 目录下有成千上万个文件或子目录,那么展开后的命令行参数数量会非常庞大。例如:

  • 10 万个文件 → 10 万个参数传递给 du
  • 每个路径平均 50 字节 → 参数总长度约 5 MB

而 Linux 对单个进程的命令行参数和环境变量总长度有限制(由 ARG_MAX 定义,通常为 2 MB 或更大,可通过 getconf ARG_MAX 查看)。

如果参数总长度超过 ARG_MAX,bash 会直接报错:Argument list too long

但在未达到上限的情况下,bash 仍需在内存中构建这个庞大的参数列表,用于后续 execve() 调用。

3. bash 构建参数列表时占用内存

在执行命令前,bash 需要:

  • 读取 /data/ 目录内容(通过 readdir 等系统调用)
  • 构建一个包含所有匹配路径的字符串数组(argv[]
  • 将这个数组保留在内存中,直到 execve 成功或失败

这个过程会导致 bash 进程自身的内存使用(RES 和 VIRT)显著上升,尤其是在目录项极多时。

4. 重定向 > xx.txt 由 bash 处理

输出重定向也是由 bash 在 fork 子进程前设置好文件描述符,但这部分开销很小,不是内存增长主因。


二、内存增长原因总结

原因说明
通配符展开在 bash 内存中完成bash 必须将 /data/* 展开为完整路径列表,存储在内存中
大量目录项导致 argv 数组巨大每个文件/目录名都成为 du 的一个参数,bash 需分配内存存储这些字符串
RES/VIRT 增长反映在 bash 进程上因为展开发生在 fork/exec du 之前,内存分配属于 bash 自身
du 尚未启动或刚启动在 top 中可能看到 bash 内存飙升,而 du 还没完全接管工作

⚠️ 注意:即使 du 后续运行并消耗内存,初始的内存 spike 通常出现在 bash 进程上,因为它要准备参数。


三、验证与解决方案

✅ 验证方法:

  1. 检查 /data/ 下文件数量:

    ls -1 /data | wc -l
    
  2. 查看系统 ARG_MAX:

    getconf ARG_MAX
    
  3. 使用 strace 观察 bash 行为(谨慎在生产环境使用):

    strace -f -e trace=execve,openat bash -c 'du -sh /data/* > xx.txt'
    

✅ 优化方案(避免 bash 内存暴涨):

  1. 避免通配符展开,改用 find + xargs

    find /data -maxdepth 1 -mindepth 1 -print0 | xargs -0 du -sh > xx.txt
    
    • xargs 会自动分批处理参数,避免单次参数过长
    • -print0 和 -0 支持含空格/特殊字符的文件名
  2. 直接对父目录统计(如果需求允许):

    du -sh /data > xx.txt
    
    • 这会递归统计整个 /data,但不会展开子项为参数
  3. 使用脚本循环处理(适用于需逐个统计):

    for f in /data/*; dodu -sh "$f"
    done > xx.txt
    
    • 每次只传一个参数给 du,bash 内存压力小
    • 但性能较低(多次调用 du)

四、结论

du -sh /data/* > xx.txt 导致 bash 进程内存显著增长,根本原因是 bash 在执行命令前需将 /data/* 展开为大量路径参数,这些参数存储在 bash 进程内存中,造成 VIRT/RES 上升。

这不是 du 的问题,而是 shell 通配符展开机制 在面对海量文件时的副作用。建议改用 find + xargs 等更稳健的方式处理大目录。

http://www.dtcms.com/a/491379.html

相关文章:

  • 网站建设公司品牌长春网站快速排名提升
  • 江协科技STM32课程笔记(四)—定时器TIM(输入捕获)
  • 山西电力建设三公司网站整站seo需要多少钱
  • Spring Boot 布隆过滤器最佳实践指南
  • spring boot框架中本地缓存@Cacheable原理与踩坑点详细解析
  • 我的远程开发革命:从环境配置噩梦到一键共享的蜕变
  • PVZ植物大战僵尸全集版分享下载 原版民间修改版含安卓手机+电脑+ios各平台
  • 网站建设公司专业公司排名wordpress 活动报名
  • 网站建设预付网站后台制作教程
  • 免费游戏网站制作化妆品做网站流程
  • 系统架构设计师备考第43天——软件架构演化和定义
  • 【Java笔记】消息队列
  • 网络监控工具:ping、traceroute、nmap、Wireshark 网络探测与分析
  • sward安装与配置,3分钟即可完成
  • 佛山网站建设方案me微擎怎么做网站
  • 影响网站访问速度网站开发所需经费
  • HTML5基础——7、CSS选择器
  • 千岛湖建设集团有限公司网站推广哪个网站好
  • 临清网站推广在哪里制作网页
  • 东莞微信网站建设报价建网络商城网站
  • PandaWiki:AI 驱动的开源知识库系
  • 中国旅游网站建设镇江网站排名优化费用
  • 今天遇到的一台爱普生L3258彩色喷墨打印机连续打印五灯齐闪故障的维修
  • 贵州建设水利厅考试网站购物网站的建设时间
  • DNS记录全解析:从A到MX
  • 使用OpenAI API和Python构建你的AI助手
  • Spring Boot入门指南:极速上手开发
  • 中电金信:从AI赋能到AI原生——企业级工具链平台重塑与建设实践
  • jsp 响应式网站模板两个网站开发swot分析
  • 建行个人网上银行登录入口亚马逊关键词快速优化