【问题标题】:How allocate more memory to my docker container running the gcc command?如何为运行 gcc 命令的 docker 容器分配更多内存?
【发布时间】:2020-07-29 02:34:46
【问题描述】:

我必须编译包含 python 函数的 C 代码。我有一台 Ubuntu 19 64 位机器,我需要为运行 raspbian 拉伸的树莓派 3model b+ 编译 C 代码。为此,我按照https://raspberrypi.stackexchange.com/a/109524/116139 创建了一个带有我需要的拉伸版本的 docker 容器。我的码头工人stats 是:


CONTAINER ID        NAME                CPU %               MEM USAGE / LIMIT     MEM %                 NET I/O             BLOCK I/O           PIDS
14b303f257da        DOCKER_CONTAINER   0.00%               13.68MiB / 7.776GiB   0.17%               6.51MB / 26.6kB     19.4MB / 41kB       2

容器环境内部,运行top

    1 root      20   0 4241352  12308   4892 S  0.0  0.2   0:00.50 bash         
  133 root       0   0 4241096  12048   4972 R  0.0  0.1   0:00.00 top 

另外,运行df -h:

Filesystem      Size  Used Avail Use% Mounted on
overlay          30G   21G  7.6G  74% /
tmpfs            64M     0   64M   0% /dev
tmpfs           3.9G     0  3.9G   0% /sys/fs/cgroup
shm              64M     0   64M   0% /dev/shm
/dev/sda1        30G   21G  7.6G  74% /etc/hosts
tmpfs           3.9G     0  3.9G   0% /proc/asound
tmpfs           3.9G     0  3.9G   0% /proc/acpi
tmpfs           3.9G     0  3.9G   0% /proc/scsi
tmpfs           3.9G     0  3.9G   0% /sys/firmware

所以,我给了你关于我系统的所有记忆信息。我的 gcc 命令在编译我的大型 C 代码时内存不足:

gcc -Os $(python3-config --cflags --ldflags) CCODE.c -o EXECUTABLE_CODE 

cc1: out of memory allocating 66660800 bytes after a total of 290631680 bytes

在 RPi4(4GB RAM)中仅运行 gcc 命令(没有 docker)它可以工作(而在 RPi3b+、1GB RAM 上,它无法报告 cc1: out of memory)。但是,我需要 RPi3,不幸的是它有不同的操作系统。 我被困在这个问题上好几个星期了。有人有任何提示或不同的解决方案吗?感谢您的建议。

【问题讨论】:

  • 没有 LPAE 的 32 位 ARM 系统无法处理超过 4 GiB 的内存。如果这是您要达到的限制,那么尝试交叉编译可能是最简单的。如果您不想在交叉编译机器上修复依赖关系,您也可以使用 distcc。我对 Qemu+Docker 的了解不够多,无法评论最大内存、Qemu 如何处理 LPAE、Raspbian 如何处理 LPAE 等。您也可以尝试添加一个大交换分区,看看是否能解决任何问题。
  • 感谢@tttapa 的回复但是我认为这不是问题,因为 RPI4 运行 32 位操作系统并且在该环境中 gcc 命令可以正常工作。无论如何,你知道我的 rpi3 的交叉编译(还包括 python.h 库)的一些好的指南吗?

标签: python c docker gcc compiler-errors


【解决方案1】:

您可以尝试交叉编译代码来解决此问题。

对于工具链,您可以使用Crosstool-NG。让 Python 进行交叉编译需要更多的工作,我不会在这里详细介绍它。我会向您推荐我使用的Dockerfileshell scripts。你可以找到更多关于他们的信息here

出于此答案的目的,我将使用自己构建的 Docker 映像。它们可从 Docker Hub 获得。如果您愿意,您当然可以自己构建它们,源代码可在我之前链接到的 GitHub 存储库中找到。如果您不需要 NumPy 和 OpenCV,请务必在 Dockerfile 中将所有内容注释掉,因为交叉编译需要很长时间。

我使用的工具链适用于 Linux 4.15 及更高版本。如果你使用 Raspbian Stretch,它的内核可能太旧了。不过,它应该可以在 Raspbian Buster 和 Ubuntu 18.04 及更高版本上运行。如果您真的想使用 Stretch,则必须按照 here 的说明编辑工具链配置文件并自己构建工具链。 Python 版本也是如此。默认情况下,它使用 Python 3.8.2。


1。准备工作目录

准备一个文件夹,其中包含您要交叉编译的所有代码。如果您有可以轻松移动的外部依赖项,请将它们也放在文件夹中。稍后我们将把这个文件夹挂载到 Docker 容器中。

2。在一个小的 shell 脚本中编写构建命令

创建一个文件build-docker.sh,其中包含您要在 Docker 容器中执行以构建代码的任何命令。

set -ex
PY_CONFIG="${RPI_SYSROOT}/usr/local/bin/python3.8-config"
OPTS=$(${PY_CONFIG} --cflags --ldflags)
CC=${HOST_TRIPLE}-gcc
${CC} ${OPTS} CCODE.c -o EXECUTABLE_CODE

注意我是如何在 Raspberry Pi 的 sysroot 文件夹中使用 python3.8-config 脚本的。如果您只使用python3.8-config 而不指定完整路径,它将使用构建机器的 Python 安装的配置,这不是您想要的。

您还需要指定交叉编译器。同样,如果您只写gcc,它使用构建系统的本机 x86_64 编译器。您需要 ARM 交叉编译器。

3。在 Docker 容器中运行脚本

您的工作目录现在应该如下所示:

.
├── build-docker.sh
└── CCODE.c

现在我们将使用必要的交叉编译工具启动一个 Docker 容器,将工作目录挂载到其中,这样您就可以访问您的 CCODE.c,并在我们刚刚编写的脚本中运行构建命令。

docker run \
    --rm \
    -it \
    -v "$PWD:/tmp/workdir" \
    -w "/tmp/workdir" \
    tttapa/rpi-cross:armv8-rpi3-linux-gnueabihf \
    "bash" "build-docker.sh"

第一次运行时,它会从 Docker Hub 拉取镜像,因此需要一些时间(超过 GiB)。

构建完成后,您的工作目录中应该会留下一个文件 EXECUTABLE_CODE

$ file EXECUTABLE_CODE
EXECUTABLE_CODE: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV),
dynamically linked, interpreter /lib/ld-linux-armhf.so.3,
for GNU/Linux 4.15.18, with debug_info, not stripped

您可以在此处找到更详细的示例:https://github.com/tttapa/RPi-Cpp-Toolchain/tree/master/extra/python/cross-compile-module/spam


一个小建议:如果你写了很多代码需要 C/C++ 和 Python 交互,或者嵌入 Python 解释器的代码,Pybind11 是一个很好的工具。它具有所有标准 C++ 容器和 Python/NumPy/Eigen 类型的绑定,它允许您从 C++ 代码调用 Python 代码,将 C/C++ 函数/结构/类导出为 Python 模块,并使用 CMake 为您处理所有编译: https://github.com/pybind/cmake_example


编辑:如果你的秘密 CCODE 需要嵌入 Python,你必须链接到 libpython:

https://docs.python.org/3.8/whatsnew/3.8.html#debug-build-uses-the-same-abi-as-release-build

要将 Python 嵌入到应用程序中,必须将新的 --embed 选项传递给 python3-config --libs --embed 以获取 -lpython3.8(将应用程序链接到 libpython)。

OPTS=$(${PY_CONFIG} --cflags --ldflags --embed)

【讨论】:

  • 我按照你的指示运行你的容器 'docker run --rm -it -v "$PWD:/tmp/workdir" -w "/tmp/workdir" tttapa/rpi-cross:armv8 -rpi3-linux-gnueabihf "bash" "build-docker.sh"' 它适用于编译纯 C 代码(例如经典的 helloword.c),它在我的 RPi3 上运行,但是编译 python 代码,转换为 'C'带有 cython 的代码无法报告大量警告和一个错误“CCODE.c:318:11: error: too many arguments to function PyCode_New” 318 | PyCode_New(a, 0, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)。你有解决方案吗? @tttapa '
  • @Leo94 这是 Cython 和 Python 3.8 的一个已知问题:github.com/cython/cython/issues/2938
  • 那么,我该如何编译我的“PY”代码?一种可能的方法是构建一个类似于您的具有 python 3.5 的我的容器? @tttapa
  • @Leo94 升级到最新的 Cython 版本并再次生成 C 代码。你为什么不使用 setuptools 来 Cythonize 和构建你的代码? cython.readthedocs.io/en/latest/src/quickstart/build.html
  • @Leo94 我刚刚用 Cython 0.29.16 和 Python 3.8 尝试过,它似乎工作正常。我已将其添加到 GitHub 存储库。 github.com/tttapa/RPi-Cpp-Toolchain/tree/master/extra/python/…你用的是什么版本的 Cython?
猜你喜欢
  • 2017-11-15
  • 2018-03-29
  • 2012-10-09
  • 1970-01-01
  • 2015-12-21
  • 2022-08-16
  • 1970-01-01
  • 2014-11-27
相关资源
最近更新 更多