使用cgroup限制内存使用

本文通过实验探讨了Linux cgroup内存子系统中,当所有进程都被设置为不可oomkill时,是否会因内存不足导致进程阻塞。进一步验证了若有可oomkill的进程存在,则被阻塞的进程能够恢复。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 
调研目标:
1、检查memory cgroup管理的进程都设置为不可oom kill时,当出现oom,是否会造成进程或进程组阻塞。
2、若出现阻塞,是否可自恢复。
 
一、准备过程
0、运行lssubsys --all,检查是否安装了cgroup的组件;没有安装则 apt-get install -y cgroup-bin。
1、准备三个程序,其中两个分别可抢占内存256MB、128MB,最后一个可从0开始逐渐增大内存占用。
2、对debian系统打开cgroup memmory子系统。(debian默认是关闭该子系统的)。
操作: vim /etc/default/grub
修改GRUB_CMDLINE_LINUX的值为"cgroup_enable=memory"。保存。
执行update-grub; 执行reboot。
3、创建一个memory限制的cgroup。(执行完步骤2后,memory root cgroup会自动创建并挂载)。
操作: cd /sys/fs/cgroup/memory/
mkdir ts_mem_cg
echo 400M > memroy.limit_in_bytes
 
二、测试过程
1、在ts_mem_cg下启动进程,并设置为不可oom_kill。
操作:
cgexec -g memory:ts_mem_cg /home/test/256MBMem
cgexec -g memory:ts_mem_cg /home/test/128MBMem
ps aux |grep 256MBMem, 找到pid,echo -1000 > /proc/pid/oom_score_adj
ps aux |grep 128MBMem, 找到pid,echo -1000 > /proc/pid/oom_score_adj
 
对第三个进程,直接启动/home/test/auto_encrease_mem,该程序会被getchar()阻塞。再打开一个终端界面执行下面的操作。
ps aux |grep auto_encrease_mem, 找到auto_encrease_mem的pid。echo -1000 > /proc/pid/oom_score_adj。
把进程auto_encrease_mem添加到ts_mem_cg: cgclassify -g memory:ts_mem_cg pid
回到第一个终端响应getchar(),让程序开始执行,逐渐抢占内存。(这样操作是为了防止启动后来不及做oom设置就先oom了)。
 
2、利用top或free观察内存使用情况。
3、auto_encrease_mem程序不断申请内存并输出提示,最后提示信息的输出中断。说明发生了oom。
4、对auto_encrease_mem程序增加printf()输出,多次测试,观察输出提示中断对应的位置。反复测试确认位置。
5、调整128MB进程的oom_score_adj(,改为默认值0和线上值-900),使其变成可oom kill。多次测试,检查cgroup进程组的变化,被阻塞的进程auto_encrease_mem是否能脱离阻塞状态。
 
三、结果分析
1、多次测试后,发现auto_encrease_mem阻塞在malloc()操作。
此时,三个程序总共占用内存257+129+16=402MB;auto_encrease_mem进程cpu占用53%(top显示)。
2、第5步操作后,进程128MBMem随即被oom kill;进程auto_encrease_mem恢复正常运行(继续申请内存并输出已用内存量提示信息)。
 
四、结论
1、依据上述测试,认定在memory cgroup限定的内存使用完时(临近oom),如果该cgroup管理的进程都不可oom kill,那么cgroup进程组的进程就有机会在申请内存时被阻塞。
2、如果memory cgroup进程组内有进程可被oom kill,则这些进程在oom发生时会被kill掉。内存空余后,之前因oom被阻塞的进程可以恢复执行。

 
说明: 以上测试在没有开启swap盘的情况下进行。
 
 
 
 
 
 
2016-05-10

hzzengchao1
<think>我们正在解决如何限制编译使用的内存问题。编译过程中,尤其是大型项目,可能会消耗大量内存,导致系统不稳定甚至崩溃。以下是一些有效的限制内存使用的方法:###方法1:使用编译工具的内置选项某些编译工具(如GCC、Clang)有内置的内存限制选项: ```bash# GCC使用-fmem-limit选项(实验性) gcc-fmem-limit=2048KBsource.c -o output#或使用环境变量(适用于某些版本) GCC_MAX_MEMORY=2G make-j4``` ###方法2:通过系统工具限制####使用 `ulimit`(临时限制) ```bash#设置当前会话的最大虚拟内存(例如2GB) ulimit -v2097152#单位是KB (2097152KB=2GB) #然后运行编译命令make-j8``` ####使用`cgroups`(更精确控制) ```bash#创建 cgroup内存限制组sudocgcreate -g memory:/compile_limitsudocgset-rmemory.max=2G compile_limitsudo cgset-rmemory.swap.max=0compile_limit#可选,禁止使用交换#在限制下运行编译cgexec -g memory:/compile_limitmake -j8```###方法3:使用容器化编译(Docker)在Docker容器中设置内存限制:```Dockerfile#Dockerfile示例FROMbuild_imageRUNbuild_your_project```运行容器时设置内存限制:```bashdockerrun -it --memory="2g" --memory-swap="2g" build_container```###方法4:分步编译(减少并行度) 降低并行编译任务数(`-j`参数)以减少内存峰值: ```bash#使用更少的并行任务make -j2#只使用2个任务```###方法5:使用编译缓存(如 ccache)减少重复编译,间接降低内存使用:```bash#设置ccacheexportCCACHE_DIR=/path/to/cacheexportCC="clang -ccache"#或者对gcc类似#编译(ccache会自动缓存结果) make-j8```###推荐方案组合1. **开发环境**:`ulimit` +降低并行度2. **持续集成**:`cgroups`或Docker内存限制3. **大型项目**:分模块编译 +编译缓存> **注意**:内存限制可能导致编译变慢或失败(当内存不足时),需根据项目特性调整。 §§相关问题§§1.如何监控编译过程中的实时内存使用情况?2.在Docker容器中编译时,如何动态调整内存限制而不重启容器?3.使用`cgroups`限制内存时,如何防止编译进程因内存不足被OOMkiller终止?4.除了内存限制,还有哪些方法可以优化大型项目的编译资源占用?5.GCC的 `-fmem-limit`选项在不同版本中的支持度如何?有哪些替代方案?</think>### 限制编译内存使用的系统化方案 #### 一、编译器级限制(推荐) 1. **GCC/Clang 内存限制参数** ```bash # 限制每个编译进程的内存 (单位KB) gcc -fmem-limit=1048576 source.c # 限制1GB clang -fmem-limit=2097152 source.cpp # 限制2GB ``` 2. **CMake 全局配置** 在 `CMakeLists.txt` 中添加: ```cmake if(CMAKE_C_COMPILER_ID STREQUAL "GNU") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fmem-limit=1572864") # 1.5GB endif() ``` #### 二、系统级限制 1. **ulimit 临时限制** ```bash # 设置当前会话内存限制 (单位KB) ulimit -v 2097152 # 2GB限制 make -j8 ``` 2. **cgroups 精确控制** ```bash # 创建内存控制组 sudo cgcreate -g memory:/compile_limits sudo cgset -r memory.max=3G compile_limits sudo cgset -r memory.swap.max=0 compile_limits # 禁用swap # 在限制下运行编译 cgexec -g memory:/compile_limits make -j12 ``` #### 三、构建工具优化 1. **Ninja 构建系统** ```bash cmake -G Ninja -DCMAKE_MAKE_PROGRAM=ninja .. ninja -j 10 -l 8 # -l 限制负载 ``` 2. **分模块编译** ```bash # 只编译特定目标 make module1 module2 -j4 ``` #### 四、容器化方案(Docker) ```dockerfile # Dockerfile FROM build_image RUN echo 2147483648 > /sys/fs/cgroup/memory/memory.limit_in_bytes && \ make -j $(nproc) ``` ```bash docker run --memory="2g" --memory-swap="2g" builder ``` #### 五、内存监控与保护 ```bash # 使用 timeout 和内存监控 timeout 2h bash -c ' while sleep 5; do if [[ $(ps -o rss= -p $PPID) -gt 2000000 ]]; then kill -SIGSTOP $PPID fi done ' & make -j10 ``` > **最佳实践**:结合编译器限制cgroups控制,建议设置 `内存限制 = 物理内存 * 0.7 / 并行任务数`
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值