【问题标题】:How to check the size of packages linked into my Go code如何检查链接到我的 Go 代码的包的大小
【发布时间】:2022-01-20 06:25:48
【问题描述】:

跟进How do I check the size of a Go project?

结论是:

为了真正了解导入某些包有多少额外的重量,还必须查看 pkg 的所有子依赖项。

这完全可以理解。我的问题是,

我是否可以知道每个组件在我编译的二进制文件、Go 运行时、依赖项和子依赖项包以及我自己的代码中占用了多少空间。

我依稀记得以前读过类似的东西(也许当 go 增强了它的链接器时)。
如果以前从未有过这样的讨论,那么 go 甚至 c 链接器有什么方法可以查看我编译的二进制文件,并揭示一些我可以进一步解析的内容吗?

【问题讨论】:

    标签: go binary linker dependencies executable


    【解决方案1】:

    二进制文件将包含调试符号,我们可以使用它来确定每个包占用了多少空间。

    我编写了一个基本程序来执行此操作,因为我不知道有任何工具可以执行此操作:

    package main
    
    import (
        "debug/elf"
        "fmt"
        "os"
        "runtime"
        "sort"
        "strings"
    
        "github.com/go-delve/delve/pkg/proc"
    )
    
    func main() {
        // Use delve to decode the DWARF section
        binInfo := proc.NewBinaryInfo(runtime.GOOS, runtime.GOARCH)
        err := binInfo.AddImage(os.Args[1], 0)
        if err != nil {
            panic(err)
        }
    
        // Make a list of unique packages
        pkgs := make([]string, 0, len(binInfo.PackageMap))
        for _, fullPkgs := range binInfo.PackageMap {
            for _, fullPkg := range fullPkgs {
                exists := false
                for _, pkg := range pkgs {
                    if fullPkg == pkg {
                        exists = true
                        break
                    }
                }
                if !exists {
                    pkgs = append(pkgs, fullPkg)
                }
            }
        }
        // Sort them for a nice output
        sort.Strings(pkgs)
    
        // Parse the ELF file ourselfs
        elfFile, err := elf.Open(os.Args[1])
        if err != nil {
            panic(err)
        }
    
        // Get the symbol table
        symbols, err := elfFile.Symbols()
        if err != nil {
            panic(err)
        }
    
        usage := make(map[string]map[string]int)
    
        for _, sym := range symbols {
            if sym.Section == elf.SHN_UNDEF || sym.Section >= elf.SectionIndex(len(elfFile.Sections)) {
                continue
            }
    
            sectionName := elfFile.Sections[sym.Section].Name
    
            symPkg := ""
            for _, pkg := range pkgs {
                if strings.HasPrefix(sym.Name, pkg) {
                    symPkg = pkg
                    break
                }
            }
            // Symbol doesn't belong to a known package
            if symPkg == "" {
                continue
            }
    
            pkgStats := usage[symPkg]
            if pkgStats == nil {
                pkgStats = make(map[string]int)
            }
    
            pkgStats[sectionName] += int(sym.Size)
            usage[symPkg] = pkgStats
        }
    
        for _, pkg := range pkgs {
            sections, exists := usage[pkg]
            if !exists {
                continue
            }
    
            fmt.Printf("%s:\n", pkg)
            for section, size := range sections {
                fmt.Printf("%15s: %8d bytes\n", section, size)
            }
            fmt.Println()
        }
    }
    

    现在实际使用的空间被划分为多个部分(.text 用于代码,.bss 用于零初始化数据,.data 用于全局变量等)。此示例列出了每个部分的大小,但如果您愿意,可以修改代码以获取总数。

    这是它从自己的二进制文件生成的输出:

    bufio:
              .text:    12733 bytes
         .noptrdata:       64 bytes
               .bss:      176 bytes
            .rodata:       72 bytes
    
    bytes:
               .bss:       48 bytes
            .rodata:       64 bytes
              .text:    12617 bytes
         .noptrdata:      320 bytes
    
    compress/flate:
              .text:    20385 bytes
         .noptrdata:      248 bytes
               .bss:     2112 bytes
          .noptrbss:       12 bytes
            .rodata:       48 bytes
    
    compress/zlib:
              .text:     4138 bytes
         .noptrdata:       96 bytes
               .bss:       48 bytes
    
    container/list:
              .text:     4016 bytes
    
    context:
              .text:      387 bytes
         .noptrdata:       72 bytes
               .bss:       40 bytes
    
    crypto:
              .text:    20982 bytes
         .noptrdata:      416 bytes
               .bss:       96 bytes
            .rodata:       58 bytes
          .noptrbss:        3 bytes
    
    debug/dwarf:
            .rodata:     1088 bytes
              .text:   113878 bytes
         .noptrdata:      247 bytes
               .bss:       64 bytes
    
    debug/elf:
            .rodata:      168 bytes
              .text:    36557 bytes
         .noptrdata:      112 bytes
              .data:     5160 bytes
               .bss:       16 bytes
    
    debug/macho:
              .text:    22980 bytes
         .noptrdata:       96 bytes
              .data:      456 bytes
            .rodata:       80 bytes
    
    debug/pe:
              .text:    26004 bytes
         .noptrdata:       96 bytes
            .rodata:      288 bytes
    
    encoding/base64:
               .bss:       32 bytes
            .rodata:       48 bytes
              .text:      846 bytes
         .noptrdata:       56 bytes
    
    encoding/binary:
              .text:    27108 bytes
         .noptrdata:       72 bytes
               .bss:       56 bytes
            .rodata:      136 bytes
    
    encoding/hex:
               .bss:       16 bytes
              .text:      288 bytes
         .noptrdata:       64 bytes
    
    encoding/json:
            .rodata:      108 bytes
              .text:     2930 bytes
         .noptrdata:      128 bytes
               .bss:       80 bytes
    
    errors:
            .rodata:       48 bytes
              .text:      744 bytes
         .noptrdata:       40 bytes
               .bss:       16 bytes
    
    fmt:
              .text:    72010 bytes
         .noptrdata:      136 bytes
              .data:      104 bytes
               .bss:       32 bytes
            .rodata:      720 bytes
    
    github.com/cilium/ebpf:
              .text:   170860 bytes
         .noptrdata:     1405 bytes
               .bss:      608 bytes
            .rodata:     3971 bytes
              .data:       16 bytes
          .noptrbss:        8 bytes
    
    github.com/go-delve/delve/pkg/dwarf/frame:
              .text:    18304 bytes
         .noptrdata:       80 bytes
               .bss:        8 bytes
            .rodata:      211 bytes
    
    github.com/go-delve/delve/pkg/dwarf/godwarf:
              .text:    40431 bytes
         .noptrdata:      144 bytes
            .rodata:      352 bytes
    
    github.com/go-delve/delve/pkg/dwarf/line:
               .bss:       48 bytes
            .rodata:      160 bytes
              .text:    24069 bytes
         .noptrdata:       96 bytes
    
    github.com/go-delve/delve/pkg/dwarf/loclist:
         .noptrdata:       64 bytes
            .rodata:       64 bytes
              .text:     4538 bytes
    
    github.com/go-delve/delve/pkg/dwarf/op:
              .text:    31142 bytes
         .noptrdata:       80 bytes
               .bss:       72 bytes
            .rodata:     5313 bytes
    
    github.com/go-delve/delve/pkg/dwarf/reader:
         .noptrdata:       72 bytes
               .bss:       16 bytes
            .rodata:       24 bytes
              .text:     8037 bytes
    
    github.com/go-delve/delve/pkg/dwarf/regnum:
               .bss:       40 bytes
            .rodata:     2760 bytes
              .text:     3943 bytes
         .noptrdata:       48 bytes
    
    github.com/go-delve/delve/pkg/dwarf/util:
              .text:     4028 bytes
         .noptrdata:       64 bytes
            .rodata:       96 bytes
    
    github.com/go-delve/delve/pkg/elfwriter:
              .text:     3394 bytes
         .noptrdata:       48 bytes
            .rodata:       48 bytes
    
    github.com/go-delve/delve/pkg/goversion:
         .noptrdata:      104 bytes
               .bss:       64 bytes
            .rodata:      160 bytes
              .text:     4415 bytes
    
    github.com/go-delve/delve/pkg/logflags:
               .bss:       32 bytes
            .rodata:       40 bytes
              .text:     2610 bytes
         .noptrdata:      136 bytes
          .noptrbss:        3 bytes
    
    github.com/go-delve/delve/pkg/proc:
              .text:   432477 bytes
         .noptrdata:      718 bytes
              .data:     1448 bytes
               .bss:      592 bytes
            .rodata:    10106 bytes
    
    github.com/go-delve/delve/pkg/version:
              .text:     1509 bytes
         .noptrdata:       72 bytes
              .data:      112 bytes
            .rodata:       40 bytes
    
    github.com/hashicorp/golang-lru/simplelru:
              .text:     3911 bytes
         .noptrdata:       32 bytes
            .rodata:      160 bytes
    
    github.com/sirupsen/logrus:
          .noptrbss:       20 bytes
            .rodata:      696 bytes
              .text:    40175 bytes
         .noptrdata:      204 bytes
              .data:       64 bytes
               .bss:       56 bytes
    
    go/ast:
              .text:    24407 bytes
         .noptrdata:      104 bytes
              .data:      112 bytes
            .rodata:      120 bytes
    
    go/constant:
               .bss:        8 bytes
            .rodata:      824 bytes
              .text:    33910 bytes
         .noptrdata:       88 bytes
    
    go/parser:
            .rodata:     1808 bytes
              .text:    78751 bytes
         .noptrdata:      136 bytes
               .bss:       32 bytes
    
    go/printer:
              .text:    77202 bytes
         .noptrdata:      113 bytes
              .data:       24 bytes
            .rodata:     1504 bytes
    
    go/scanner:
            .rodata:      240 bytes
              .text:    18594 bytes
         .noptrdata:       93 bytes
              .data:       24 bytes
    
    go/token:
         .noptrdata:       72 bytes
              .data:     1376 bytes
               .bss:        8 bytes
            .rodata:      192 bytes
              .text:     7154 bytes
    
    golang.org/x/arch/arm64/arm64asm:
            .rodata:      856 bytes
              .text:   116428 bytes
         .noptrdata:       80 bytes
               .bss:       80 bytes
              .data:    46128 bytes
    
    golang.org/x/arch/x86/x86asm:
         .noptrdata:    29125 bytes
               .bss:      112 bytes
              .data:    20928 bytes
            .rodata:     1252 bytes
              .text:    76721 bytes
    
    golang.org/x/sys/unix:
              .text:     1800 bytes
         .noptrdata:      128 bytes
            .rodata:       70 bytes
              .data:       80 bytes
    
    hash/adler32:
              .text:     1013 bytes
         .noptrdata:       40 bytes
    
    internal/bytealg:
            .rodata:       56 bytes
          .noptrbss:        8 bytes
              .text:     1462 bytes
         .noptrdata:       32 bytes
    
    internal/cpu:
            .rodata:      500 bytes
          .noptrbss:      416 bytes
         .noptrdata:        8 bytes
               .bss:       24 bytes
              .text:     3017 bytes
    
    internal/fmtsort:
              .text:     7443 bytes
         .noptrdata:       40 bytes
            .rodata:       40 bytes
    
    internal/oserror:
              .text:      500 bytes
         .noptrdata:       40 bytes
               .bss:       80 bytes
    
    internal/poll:
              .text:    31565 bytes
            .rodata:      192 bytes
         .noptrdata:      112 bytes
              .data:       96 bytes
               .bss:       64 bytes
          .noptrbss:       12 bytes
    
    internal/reflectlite:
              .text:    13761 bytes
         .noptrdata:       32 bytes
              .data:      456 bytes
               .bss:       24 bytes
            .rodata:      496 bytes
    
    internal/syscall/unix:
            .rodata:       72 bytes
              .text:      708 bytes
         .noptrdata:       40 bytes
          .noptrbss:        4 bytes
    
    internal/testlog:
              .text:      827 bytes
         .noptrdata:       32 bytes
          .noptrbss:       12 bytes
               .bss:       16 bytes
            .rodata:       72 bytes
    
    io:
         .noptrdata:      240 bytes
               .bss:      272 bytes
              .data:       56 bytes
          .noptrbss:        0 bytes
            .rodata:      128 bytes
              .text:    10824 bytes
    
    log:
              .text:      188 bytes
         .noptrdata:       80 bytes
               .bss:        8 bytes
    
    main:
              .text:     3002 bytes
         .noptrdata:       80 bytes
            .rodata:      104 bytes
    
    math:
              .data:      136 bytes
               .bss:     2672 bytes
              .text:   184385 bytes
         .noptrdata:    10211 bytes
            .rodata:     2076 bytes
          .noptrbss:        2 bytes
    
    net:
              .text:    24417 bytes
         .noptrdata:      236 bytes
              .data:      240 bytes
               .bss:      584 bytes
          .noptrbss:       16 bytes
            .rodata:       48 bytes
    
    os:
               .bss:      264 bytes
              .data:       32 bytes
            .rodata:      352 bytes
              .text:    46276 bytes
         .noptrdata:      296 bytes
          .noptrbss:        1 bytes
    
    path:
              .text:     9378 bytes
         .noptrdata:      136 bytes
               .bss:       48 bytes
            .rodata:       48 bytes
    
    reflect:
          .noptrbss:        1 bytes
              .text:    97417 bytes
         .noptrdata:       72 bytes
            .rodata:     1728 bytes
              .data:      456 bytes
               .bss:      160 bytes
    
    regexp:
            .rodata:      968 bytes
              .text:   126451 bytes
         .noptrdata:      558 bytes
               .bss:      296 bytes
          .noptrbss:       16 bytes
              .data:      816 bytes
    
    runtime:
          .noptrbss:    20487 bytes
              .data:     8520 bytes
               .bss:   184836 bytes
              .tbss:        8 bytes
          .typelink:     9020 bytes
         .gopclntab:        0 bytes
              .text:   408713 bytes
         .noptrdata:     4347 bytes
            .rodata:    23102 bytes
          .itablink:     2952 bytes
    
    sort:
              .text:    13055 bytes
         .noptrdata:       32 bytes
              .data:       16 bytes
            .rodata:       24 bytes
    
    strconv:
              .text:    45928 bytes
         .noptrdata:    17015 bytes
              .data:     1680 bytes
               .bss:       32 bytes
            .rodata:      144 bytes
    
    strings:
              .text:    21070 bytes
         .noptrdata:      320 bytes
            .rodata:      168 bytes
    
    sync:
            .rodata:      476 bytes
         .noptrdata:       56 bytes
               .bss:       56 bytes
          .noptrbss:        8 bytes
              .text:    14288 bytes
    
    syscall:
         .noptrdata:      127 bytes
            .rodata:      978 bytes
          .noptrbss:       76 bytes
               .bss:      264 bytes
              .data:     2720 bytes
              .text:    33728 bytes
    
    text/tabwriter:
              .data:       96 bytes
            .rodata:       88 bytes
              .text:     8002 bytes
         .noptrdata:       46 bytes
    
    text/template:
              .text:   166284 bytes
         .noptrdata:      316 bytes
          .noptrbss:        8 bytes
               .bss:      176 bytes
              .data:      376 bytes
            .rodata:     3152 bytes
    
    time:
              .text:    83290 bytes
         .noptrdata:      164 bytes
              .data:      912 bytes
               .bss:      208 bytes
          .noptrbss:       20 bytes
            .rodata:      832 bytes
    
    unicode:
         .noptrdata:    50398 bytes
              .data:    15248 bytes
               .bss:       40 bytes
          .noptrbss:        0 bytes
              .text:    27198 bytes
    

    请注意,这个程序并不完美,它只适用于 Linux/Mac,因为它依赖于 ELF。我相信您可以对 Windows PE 文件执行类似的操作,但这会花费我很多时间。

    这个程序也忽略了 go 运行时的某些部分,但我猜这对你来说不是最重要的。

    【讨论】:

      【解决方案2】:

      您可以运行nm 来获取二进制文件中所有对象的大小。 示例:nm -S /usr/local/go/bin/gofmt。第二列是大小。

      0000000000468700 000000000000011c T unicode/utf8.DecodeLastRuneInString
      0000000000468240 00000000000001a6 T unicode/utf8.DecodeRune
      0000000000468400 00000000000001a6 T unicode/utf8.DecodeRuneInString
      0000000000468820 0000000000000157 T unicode/utf8.EncodeRune
      

      【讨论】:

      • 谢谢!赞成,但让我给 Dylan 更多的分数,他编写了分析程序。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-14
      • 2021-07-20
      • 1970-01-01
      • 1970-01-01
      • 2021-11-28
      • 1970-01-01
      • 2013-04-13
      相关资源
      最近更新 更多