ARM64与AMD64在GOMAXPROCS调度、math/big性能、CGO调用约定及unsafe.Slice优化四方面存在差异:前者内存模型弱致调度延迟高、big.Mul慢20–30%、CGO类型不匹配更易panic、unsafe.Slice边界检查消除不充分。
runtime.GOMAXPROCS 表现不一致Go 程序在 ARM64(如 Apple M1/M2、AWS Graviton)和 AMD64(x86_64)上默认调度行为看似相同,但底层 CPU 缓存一致性模型、内存重排序语义、以及 atomic 指令实现差异,会导致 runtime.GOMAXPROCS 实际效果不同。尤其在高并发锁竞争或频繁 atomic.LoadUint64 场景下,ARM64 可能因更弱的内存模型出现更高延迟抖动。
memory barrier 更保守,sync/atomic 操作开销比 AMD64 高约 10–15%(实测于 Go 1.21+)GOMAXPROCS 设为大于物理核心数时,ARM64 调度器抢占延迟更敏感,容易触发更多 goroutine 迁移go tool trace 对比 ProcStart/GoPreempt 事件分布,ARM64 上 Preempt 更密集math/big 在 ARM64 上乘法性能下降明显Go 标准库中 math/big 的大整数运算大量依赖 uint64 底层操作。ARM64 架构缺乏原生 umulh(高位乘法)指令,而 AMD64 的 mulq 可单条指令返回 128 位结果。因此 (*big.Int).Mul 在 ARM64 上需额外拆分与拼接逻辑,实测吞吐低 20–30%(尤其在 2048-bit 以上 RSA 密钥运算中)。
golang.org/x/crypto/curve25519 等已做架构特化优化的库-gcflags="-l -m" 查看是否内联失败,ARM64 上部分 big.addVV 调用可能未被完全内联*big.Int,复用 big.Int.Set() 实例Go 启用 CGO 后,C 函数调用在 AMD64 使用 System V ABI(参数经寄存器传递),而 ARM64 使用 AAPCS64(前 8 个整型参数走 x0–x7,浮点走 s0–s7)。若 C 侧函数签名未严格匹配(比如误将 int64 当作 int32 传入),ARM64 上更容易因寄存器截断引发静默错误或 panic。
C.foo(C.int(x)) 中 x 是 int64,但 C 函数声明为 void foo(int) —— AMD64 可能侥幸运行,ARM64 直接读错寄存器值// #i
nclude 并显式使用 int32_t/int64_t 声明 C 函数CGO_CFLAGS="-Wall -Werror" 强制检查类型匹配unsafe.Slice 优化尚未完全对齐Go 1.21 引入 unsafe.Slice 替代 unsafe.SliceHeader,但 ARM64 后端的逃逸分析与 slice bounds check 消除仍略滞后。在循环中高频调用 unsafe.Slice(ptr, n) 时,ARM64 编译出的汇编常多出 1–2 条 cmp/b.hs 分支,而 AMD64 已基本消除。
for i := 0; i < len(data); i++ {
s := unsafe.Slice(&data[i], 4) // ARM64: 每次都检查 len(data)-i >= 4
_ = s[0]
}
(*[4]byte)(unsafe.Pointer(&data[i]))[:4:4](绕过 unsafe.Slice 的运行时检查)i+4 由外部保证
cmd/compile/internal/amd64 vs cmd/compile/internal/arm64 中 boundsCheck pass 的同步进度