【问题标题】:How can I reduce the virtual memory required by gccgo compiled executable?如何减少 gccgo 编译的可执行文件所需的虚拟内存?
【发布时间】:2018-12-12 16:36:45
【问题描述】:

当我使用 gccgo 编译这个简单的 hello world 示例时,生成的可执行文件使用了超过 800 MiB 的 VmData。我想知道为什么,如果我能做些什么来降低它。睡眠只是为了给我时间观察内存使用情况。

来源:

package main

import (
  "fmt"
  "time"
)

func main() {
  fmt.Println("hello world")
  time.Sleep(1000000000 * 5)
}

我用来编译的脚本:

#!/bin/bash

TOOLCHAIN_PREFIX=i686-linux-gnu
OPTIMIZATION_FLAG="-O3"

CGO_ENABLED=1 \
CC=${TOOLCHAIN_PREFIX}-gcc-8 \
CXX=${TOOLCHAIN_PREFIX}-g++-8 \
AR=${TOOLCHAIN_PREFIX}-ar \
GCCGO=${TOOLCHAIN_PREFIX}-gccgo-8 \
CGO_CFLAGS="-g ${OPTIMIZATION_FLAG}" \
CGO_CPPFLAGS="" \
CGO_CXXFLAGS="-g ${OPTIMIZATION_FLAG}" \
CGO_FFLAGS="-g ${OPTIMIZATION_FLAG}" \
CGO_LDFLAGS="-g ${OPTIMIZATION_FLAG}" \
GOOS=linux \
GOARCH=386 \
go build -x \
   -compiler=gccgo \
   -gccgoflags=all="-static -g ${OPTIMIZATION_FLAG}" \
   $1

gccgo的版本:

$ i686-linux-gnu-gccgo-8 --version
i686-linux-gnu-gccgo-8 (Ubuntu 8.2.0-1ubuntu2~18.04) 8.2.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

/proc//status 的输出:

VmPeak:  811692 kB
VmSize:  811692 kB
VmLck:        0 kB
VmPin:        0 kB
VmHWM:     5796 kB
VmRSS:     5796 kB
VmData:  807196 kB
VmStk:      132 kB
VmExe:     2936 kB
VmLib:        0 kB
VmPTE:       52 kB
VmPMD:        0 kB
VmSwap:       0 kB

我问是因为我的设备只有 512 MiB 的 RAM。我知道这是虚拟内存,但我想尽可能减少或删除过度使用。对我来说,一个简单的可执行文件需要这么多分配似乎是不合理的。

【问题讨论】:

  • 虚拟内存使用是非常不相关的,将 VmSize 与物理内存进行比较是完全不相关的。居民规模才是真正重要的。
  • @Adrian,这是否意味着可执行文件分配了它并且可能在某些时候使用它?此设备没有交换文件,因此如果可执行文件尝试使用 800 MiB 的 RAM,它将失败。
  • 不,它没有。它是“一个进程的虚拟大小,它是它实际使用的内存、它映射到自身的内存(例如 X 服务器的视频卡 RAM)、磁盘上已映射到它的文件的总和(最显着的共享库),以及与其他进程共享的内存。”
  • 即使没有页面文件,内存映射文件(包括二进制文件本身和任何加载的共享库)也可以交换到磁盘或从磁盘交换,因为它们已经存在于磁盘上。无需将第二个副本写入交换文件即可在虚拟内存中使用它们。
  • 我觉得您一般是在处理虚拟内存,而不是专门针对 VmData,这就是问题所在。你描述的东西是 VmExe 和 VmLib,在这里它们似乎是合理的数字,而不是我的问题的一部分。

标签: linux go virtual-memory gccgo memory-overcommitment


【解决方案1】:

我能够找到 gccgo 需要这么多内存的位置。它在 mallocinit 函数的 libgo/go/runtime/malloc.go 文件中:

// If we fail to allocate, try again with a smaller arena.
// This is necessary on Android L where we share a process
// with ART, which reserves virtual memory aggressively.
// In the worst case, fall back to a 0-sized initial arena,
// in the hope that subsequent reservations will succeed.
arenaSizes := [...]uintptr{
  512 << 20,
  256 << 20,
  128 << 20,
  0,
}

for _, arenaSize := range &arenaSizes {
  // SysReserve treats the address we ask for, end, as a hint,
  // not as an absolute requirement. If we ask for the end
  // of the data segment but the operating system requires
  // a little more space before we can start allocating, it will
  // give out a slightly higher pointer. Except QEMU, which
  // is buggy, as usual: it won't adjust the pointer upward.
  // So adjust it upward a little bit ourselves: 1/4 MB to get
  // away from the running binary image and then round up
  // to a MB boundary.
  p = round(getEnd()+(1<<18), 1<<20)
  pSize = bitmapSize + spansSize + arenaSize + _PageSize
  if p <= procBrk && procBrk < p+pSize {
    // Move the start above the brk,
    // leaving some room for future brk
    // expansion.
    p = round(procBrk+(1<<20), 1<<20)
  }
  p = uintptr(sysReserve(unsafe.Pointer(p), pSize, &reserved))
  if p != 0 {
    break
  }
}
if p == 0 {
  throw("runtime: cannot reserve arena virtual address space")
}

有趣的是,如果较大的竞技场失败,它会退回到较小的竞技场大小。所以限制 go 可执行文件可用的虚拟内存实际上会限制它成功分配的数量。

我能够使用ulimit -v 327680 将虚拟内存限制为更小的数字:

VmPeak:   300772 kB
VmSize:   300772 kB
VmLck:         0 kB
VmPin:         0 kB
VmHWM:      5712 kB
VmRSS:      5712 kB
VmData:   296276 kB
VmStk:       132 kB
VmExe:      2936 kB
VmLib:         0 kB
VmPTE:        56 kB
VmPMD:         0 kB
VmSwap:        0 kB

这些仍然是很大的数字,但是 gccgo 可执行文件可以实现的最好的数字。所以这个问题的答案是,是的,你可以减少 gccgo 编译的可执行文件的 VmData,但你真的不应该担心它。 (在 64 位机器上 gccgo 尝试分配 512 GB。)

【讨论】:

    【解决方案2】:

    可能的原因是您将库链接到代码中。我的猜测是,如果您要显式链接到静态库,那么您将能够获得更小的逻辑地址空间,以便将最少的添加到您的可执行文件中。无论如何,拥有大逻辑地址空间的危害最小。

    【讨论】:

    • 库不计入 VmData。
    猜你喜欢
    • 1970-01-01
    • 2019-04-28
    • 2015-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多