猿问

如何减少 gccgo 编译的可执行文件所需的虚拟内存?

当我使用 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/<pid>/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。我知道这是虚拟内存,但我想尽可能减少或删除过度使用。一个简单的可执行文件需要那么多分配对我来说似乎不合理。


交互式爱情
浏览 105回答 2
2回答

慕桂英3389331

我能够找到 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{&nbsp; 512 << 20,&nbsp; 256 << 20,&nbsp; 128 << 20,&nbsp; 0,}for _, arenaSize := range &arenaSizes {&nbsp; // SysReserve treats the address we ask for, end, as a hint,&nbsp; // not as an absolute requirement. If we ask for the end&nbsp; // of the data segment but the operating system requires&nbsp; // a little more space before we can start allocating, it will&nbsp; // give out a slightly higher pointer. Except QEMU, which&nbsp; // is buggy, as usual: it won't adjust the pointer upward.&nbsp; // So adjust it upward a little bit ourselves: 1/4 MB to get&nbsp; // away from the running binary image and then round up&nbsp; // to a MB boundary.&nbsp; p = round(getEnd()+(1<<18), 1<<20)&nbsp; pSize = bitmapSize + spansSize + arenaSize + _PageSize&nbsp; if p <= procBrk && procBrk < p+pSize {&nbsp; &nbsp; // Move the start above the brk,&nbsp; &nbsp; // leaving some room for future brk&nbsp; &nbsp; // expansion.&nbsp; &nbsp; p = round(procBrk+(1<<20), 1<<20)&nbsp; }&nbsp; p = uintptr(sysReserve(unsafe.Pointer(p), pSize, &reserved))&nbsp; if p != 0 {&nbsp; &nbsp; break&nbsp; }}if p == 0 {&nbsp; throw("runtime: cannot reserve arena virtual address space")}有趣的是,如果较大的竞技场失败,它会退回到较小的竞技场。因此,限制 go 可执行文件可用的虚拟内存实际上会限制它成功分配的数量。我能够使用ulimit -v 327680将虚拟内存限制为较小的数字:VmPeak:&nbsp; &nbsp;300772 kBVmSize:&nbsp; &nbsp;300772 kBVmLck:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0 kBVmPin:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0 kBVmHWM:&nbsp; &nbsp; &nbsp; 5712 kBVmRSS:&nbsp; &nbsp; &nbsp; 5712 kBVmData:&nbsp; &nbsp;296276 kBVmStk:&nbsp; &nbsp; &nbsp; &nbsp;132 kBVmExe:&nbsp; &nbsp; &nbsp; 2936 kBVmLib:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0 kBVmPTE:&nbsp; &nbsp; &nbsp; &nbsp; 56 kBVmPMD:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0 kBVmSwap:&nbsp; &nbsp; &nbsp; &nbsp; 0 kB这些仍然是很大的数字,但是 gccgo 可执行文件可以达到的最好结果。所以问题的答案是,是的,你可以减少 gccgo 编译的可执行文件的 VmData,但你真的不应该为此担心。(在 64 位机器上,gccgo 尝试分配 512 GB。)

摇曳的蔷薇

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

相关分类

Go
我要回答