23

有什么方法可以强制make -j不要过度消耗我的 RAM?我在一个开发团队工作,我们有不同的硬件集,所以-j8可能并不适合每个人。但是,make -j对我来说使用了太多的 RAM,并且溢出到交换中,这可能会导致我的整个系统崩溃。我怎样才能避免这种情况?

理想情况下,我希望观察系统负载并停止产生新线程,等待一些完成,然后继续。

4

3 回答 3

6

make -j 的作用是否可能存在一些混淆?(至少我错了很长时间......)。我假设没有选项的 -j 会适应 CPU 的数量,但事实并非如此——它根本没有应用任何限制。这意味着对于大型项目,它将创建大量进程(只需运行“top”即可查看...),并且可能会耗尽所有 RAM。当我的项目的“make -j”使用了我所有的 16Gb RAM 并失败时,我偶然发现了这一点,而“make -j 8”在 2.5 Gb RAM 使用量(在 8 个内核上,负载接近 100%两种情况)。

在效率方面,我认为使用等于或大于您期望的最大 CPU 数量的限制比没有限制更有效,因为数千个进程的调度有一些开销。创建的进程总数应该是恒定的,但是当“-j”一次创建很多进程时,内存分配可能会成为问题。即使将限制设置为 CPU 数量的两倍,也应该比根本不设置限制更加保守。

PS:经过更多挖掘后,我想出了一个巧妙的解决方案 - 只需读出处理器的数量并将其用作 -j 选项:

make -j `nproc`
于 2013-08-28T09:06:14.873 回答
6

稍微简单的解决方案是让每个工作站都有一个适合硬件可以处理的环境变量。让 makefile 读取此环境变量并将其传递给 -j 选项。如何让 gnu make 读取环境变量。

此外,如果构建过程有很多步骤并且需要很长时间make重新读取环境变量,以便在构建期间可以减少/增加资源使用量。

此外,也许有一个服务/应用程序在工作站上运行,它监视资源使用情况并修改环境变量,而不是尝试这样make做......

于 2012-07-24T21:36:21.203 回答
1

可以使用ulimit. 但是当超出限制时,可能会导致进程失败。gcc喜欢在单线程中链接时超出任何限制。所以ulimit解决方案并不流行。

另一种解决方案是提供gcc每个线程的 RAM 使用估计,并维护很少使用的交换。load-average当负载太高时,您可以添加以停止生成新线程/作业。

我正在使用以下脚本/etc/profile.d/makeopts.sh(gentoo):

#!/bin/bash

# We need up to 1000 MB (less than 1GB) per thread.
MAX_THREADS=$(($(getconf _PHYS_PAGES) * $(getconf PAGE_SIZE) / (1000 ** 3)))
EFFECTIVE_THREADS=$(getconf _NPROCESSORS_ONLN)
THREADS=$((MAX_THREADS < EFFECTIVE_THREADS ? MAX_THREADS : EFFECTIVE_THREADS))

MAX_JOBS=$((MAX_THREADS / THREADS))
JOBS=$((MAX_JOBS < EFFECTIVE_THREADS ? MAX_JOBS : EFFECTIVE_THREADS))

MAX_LOAD=$((EFFECTIVE_THREADS * 9 / 10))

export MAKEOPTS="--jobs=$THREADS --load-average=$MAX_LOAD"
export EMERGE_DEFAULT_OPTS="--jobs=$JOBS --load-average=$MAX_LOAD"

具有 4 个线程和 16 GB RAM 的机器:

MAKEOPTS="--jobs=4 --load-average=3"
EMERGE_DEFAULT_OPTS="--jobs=4 --load-average=3"

具有 16 个线程和 32 GB RAM 的机器:

MAKEOPTS="--jobs=16 --load-average=14"
EMERGE_DEFAULT_OPTS="--jobs=2 --load-average=14"

请注意,此配置是为CFLAGS="-O2 -pipe -march=native". 如果您想添加/删除轻/重选项,请重新估计它。

于 2020-08-23T11:59:35.777 回答