Docker容器中使用make -j编译GCC项目时出现内存分配错误
问题
在Docker容器内使用make -j编译项目时触发内存相关错误,错误信息如下:
/root/projects/obj/linux_debug/src/myos_make/libmyos.a: error adding symbols: Cannot allocate memory /usr/protobuf-3.9.2/lib/libprotobuf.a: error adding symbols: Bad address
但以下两种场景编译均正常:
- 容器内不使用
-j选项编译 - 宿主机上使用
-j选项编译
对应的Dockerfile内容如下:
# # This docker must be built from projects/src folder as context # FROM ubuntu:18.04 as base # copy the dockerfile to make it possible to keep track of the cntent of the image COPY ./docker_build/docker_files/Dockerfile.ubuntu18.04-builder $HOME/. # Disable Prompt During Packages Installation ARG DEBIAN_FRONTEND=noninteractive # Update Ubuntu Software repository RUN apt update -y && apt upgrade -y # Install base utils RUN apt install -y \ nano \ wget \ sudo \ curl \ && apt clean -y # Install additional packages needed for build. RUN apt install -y \ nasm \ pkg-config \ bc \ python \ python3 \ python3-pip \ sshpass \ libapr1 \ libapr1-dev \ && apt clean -y RUN apt install -y \ rpm \ libaio-dev \ libnuma-dev \ numactl \ valgrind \ openssl \ libssl-dev \ ldap-utils \ libldap2-dev \ libncurses5-dev \ libncursesw5-dev \ uuid-dev \ ncurses-base \ expat \ libfuse-dev \ cmake \ build-essential \ autotools-dev \ autoconf \ automake \ doxygen \ linux-headers-4.15.0-173-generic \ g++-multilib \ lib32z1-dev \ libasan4 \ software-properties-common \ libtool \ unzip \ xsltproc \ && apt clean -y RUN ln -s /usr/bin/doxygen /bin/doxygen # install GCC compiler RUN add-apt-repository ppa:ubuntu-toolchain-r/test -y \ && apt update -y\ && apt install gcc-10 -y \ && apt install g++-10 -y \ && apt clean -y && \ update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 60 --slave /usr/bin/g++ g++ /usr/bin/g++-10 && \ update-alternatives --config gcc RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py --output get-pip.py && \ python get-pip.py RUN ln -sf /usr/local/bin/pip2 /usr/bin/pip RUN pip install \ pyyaml \ jinja2 \ gcovr FROM base as env-prepare COPY external/protobuf /protobuf RUN cd protobuf && ./build_proto.sh FROM base as builder COPY --from=env-prepare /usr/protobuf-3.9.2/ /usr/protobuf-3.9.2/ COPY --from=env-prepare /usr/protobuf-c-1.3.2/ /usr/protobuf-c-1.3.2/ COPY docker_build/docker-image-release /etc/docker-image-release ARG UID=1000 USER ${UID} # This entrypoint is to make everything run inside bash, so the devtools script will alway run before the command ENTRYPOINT [ "/bin/bash", "-c" ]
解决方案
1. 手动扩容容器内存
Docker默认给容器分配的内存配额有限,并发编译时极易耗尽内存。启动容器时指定更大的内存:
docker run -it --memory=4g --memory-swap=4g [你的镜像名称]
可根据实际编译需求调整数值,比如8g。
2. 限制make -j的并发线程数
不要使用默认的自动线程数(通常等于CPU核心数),手动指定更保守的数值,平衡编译速度与内存占用:
make -j4
可以从-j2开始测试,逐步调整到合适的线程数。
3. 排查内存使用情况
启动容器后执行free -h,查看编译过程中内存是否被耗尽。如果宿主机本身内存不足,需先扩容宿主机内存。
4. 优化编译参数
- 临时关闭编译优化:在Makefile中添加
CFLAGS+=-O0,减少内存占用。 - 启用目标文件瘦身参数:添加
CFLAGS+=-ffunction-sections -fdata-sections,降低静态库文件大小。 - 关闭ASAN:Dockerfile中安装了
libasan4,如果编译默认启用地址 sanitizer,会大幅增加内存消耗,可临时关闭该选项。
5. 修改Docker daemon默认内存配置
如果频繁遇到这类问题,可修改Docker daemon配置文件(通常为/etc/docker/daemon.json),设置全局默认内存限制:
{ "resources": { "defaults": { "memory": "4g" } } }
修改后重启Docker服务:systemctl restart docker
内容的提问来源于stack exchange,提问作者Alex Belous
相关产品推荐
相关产品推荐

