使用 OpenJDK 8 和 Apple M1 芯片在 Docker shell 中编译 sbt 时出现 SIGSEGV 错误

jia*_*mae 11 java sbt java-8 docker apple-m1

刚刚买了一台配备 Apple M1 芯片的新 Mac,正在尝试为我正在进行的项目设置开发环境。我正在使用 Docker Desktop 并将平台标志添加到 docker-compose.yml ( platform: linux/x86_64) 和 Dockerfile (FROM --platform=linux/amd64 openjdk:8-jdk-stretch ) 中。I\xe2\x80\x99m 使用 OpenJDK 8 和 sbt 0.13.15

\n

容器创建得很好,我可以sbt -Dsbt.ivy.home=\'.ivy2\' -Dsbt.global.base=\'.sbt\' -Dsbt.repository.config=\'.sbt/repositories\'从 docker shell 内部运行,它将创建一个sbtshell,但是如果我运行compile在这个 shell 中运行,我会收到此错误:

\n
[info] Compiling 153 Scala sources and 2 Java sources to /opt/target/scala-2.10/classes...\n#\n# A fatal error has been detected by the Java Runtime Environment:\n#\n#  SIGSEGV (0xb) at pc=0x000000400d9d7447, pid=9, tid=0x00000040b87ab700\n#\n# JRE version: OpenJDK Runtime Environment (8.0_242-b08) (build 1.8.0_242-b08)\n# Java VM: OpenJDK 64-Bit Server VM (25.242-b08 mixed mode linux-amd64 compressed oops)\n# Problematic frame:\n# J 12257 C2 scala.reflect.internal.Types$$anonfun$57.apply(Ljava/lang/Object;)Ljava/lang/Object; (12 bytes) @ 0x000000400d9d7447 [0x000000400d9d7080+0x3c7]\n#\n# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again\n#\n# An error report file with more information is saved as:\n# /opt/hs_err_pid9.log\n#\n# If you would like to submit a bug report, please visit:\n#   http://bugreport.java.com/bugreport/crash.jsp\n#\nqemu: uncaught target signal 6 (Aborted) - core dumped\nAborted\n
Run Code Online (Sandbox Code Playgroud)\n

纵观整个hs_err_pid9.log它创建的代码,唯一不寻常的片段是:

\n
Event: 66.528 Thread 0x00000040a8020800 Exception <a \'java/io/FileNotFoundException\'> (0x00000000f7eaf680) thrown at [/home/openjdk/jdk8u/hotspot/src/share/vm/prims/jni.cpp, line 710]\nEvent: 66.545 Thread 0x00000040a8020800 Exception <a \'java/io/FileNotFoundException\'> (0x00000000f7eb0b38) thrown at [/home/openjdk/jdk8u/hotspot/src/share/vm/prims/jni.cpp, line 710]\nEvent: 67.214 Thread 0x00000040a801f800 Exception <a \'java/io/FileNotFoundException\'> (0x00000000f7d343b8) thrown at [/home/openjdk/jdk8u/hotspot/src/share/vm/prims/jni.cpp, line 710]\nEvent: 67.219 Thread 0x00000040a801f800 Exception <a \'java/io/FileNotFoundException\'> (0x00000000f7d35048) thrown at [/home/openjdk/jdk8u/hotspot/src/share/vm/prims/jni.cpp, line 710]\nEvent: 68.016 Thread 0x00000040a801f800 Implicit null exception at 0x000000400bd16a9b to 0x000000400bd16c51\nEvent: 69.405 Thread 0x00000040a801f800 Implicit null exception at 0x000000400c118986 to 0x000000400c118ea5\nEvent: 69.407 Thread 0x00000040a801f800 Implicit null exception at 0x000000400bdba136 to 0x000000400bdba4ed\nEvent: 69.556 Thread 0x00000040a801f800 Implicit null exception at 0x000000400bd29275 to 0x000000400bd2945d\nEvent: 69.567 Thread 0x00000040a801f800 Implicit null exception at 0x000000400be3adaf to 0x000000400be3ae19\nEvent: 69.835 Thread 0x00000040a801f800 Implicit null exception at 0x000000400be93a35 to 0x000000400be93de1\n
Run Code Online (Sandbox Code Playgroud)\n

这里是代码库,供任何想要查看设置环境的步骤以及根目录中的 docker-compose.yml 和 Dockerfile 的人使用。

\n

Dan*_*owe 5

您可能遇到了 qemu 中的已知错误。在 ARM 芯片上模拟 amd64 时存在问题。在这种情况下,解决方案是将工作负载转移到 amd64 系统,或者为 ARM 重建映像。

\n

请参阅此处的已知问题部分:

\n

https://docs.docker.com/desktop/mac/apple-silicon/

\n

截至 2022 年 2 月的相关文本:

\n
\n

然而,尝试在模拟下的 Apple 芯片机器上运行基于 Intel 的容器可能会崩溃,因为 qemu 有时无法运行容器。此外,文件系统更改通知 API (inotify) 在 qemu 模拟下不起作用。即使容器在模拟下正确运行,它们也会比本机等效容器更慢并且使用更多内存。

\n

总而言之,在基于 Arm 的机器上运行基于 Intel 的容器应该仅被视为 \xe2\x80\x9cbest尽力\xe2\x80\x9d。我们建议尽可能在 Apple 硅机器上运行 arm64 容器,并鼓励容器作者生产其容器的 arm64 或多架构版本。随着越来越多的镜像被重建以支持多种架构,我们预计这个问题会随着时间的推移而变得不那么常见。

\n
\n

将镜像重建为 ARM

\n

由于您正在构建自己的映像,因此您应该能够为 ARM 平台重建它们。

\n

您希望从 ARM 基础映像开始。您当前使用的版本 ( openjdk:8-jdk-stretch ) 不是针对 ARM 分发的,但同一存储库的其他版本是分发的(例如openjdk:19-jdk-buster)。

\n

(您也可以自己将当前基础映像重建为 ARM,但这需要您找到其源材料 - 有时可以在 GitHub、GitLab 等上找到它们。)

\n

更改您的 Dockerfile 以使用可用于 ARM 的基础映像,然后将您自己的映像重建为 ARM。这样做很简单 - 不指定平台信息,Docker 将默认使用您的平台。

\n

多平台构建

\n

为什么使用 amd64 镜像?我考虑了两个可能的原因。

\n
    \n
  1. 因为您的基础映像仅可用作 amd64
  2. \n
  3. 由于您的生产环境是 amd64,因此您希望生成的映像是 amd64。
  4. \n
\n

如果这只是第一个原因,那么上面已经介绍了。如果您为 ARM 进行重建,那么您就完成了。

\n

对于第二种情况,您可以在开发环境中使用 ARM,但在完成工作后构建用于生产的 amd64 版本。

\n

要创建多平台映像并将其推送到注册表,您可以使用buildx以下命令:

\n
docker buildx build --platform linux/amd64,linux/arm64 \\\n    -t <your image tag> --push .\n
Run Code Online (Sandbox Code Playgroud)\n

多平台映像很好,因为它们允许您使用更快、更稳定的 ARM 映像。它还允许您的任何拥有 Apple Silicon 设备的队友执行相同操作。但是您的生产平台(通常是 amd64)和 amd64 平台上的其他开发人员也可以使用相同的映像(但为其本机平台构建)。

\n


小智 1

您是否使用某些 IDE 来**在 shell 中运行编译**?

如果是这样,您可以尝试打开终端/shell 并运行错误中提到的命令

ulimit -c 无限

之后,通过命令从同一终端/shell 运行编译。要从 IDE 运行它,您需要在 IDE 设置中找到如何设置此参数