gpt4 book ai didi

go - 如何检查链接到我的 Go 代码中的包的大小

转载 作者:行者123 更新时间:2023-12-02 16:00:36 25 4
gpt4 key购买 nike

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

结论是:

in order to get a true sense of how much extra weight importing certain packages, one has to look at all of the pkg's sub-dependencies as well.

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

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

我依稀记得以前读过类似的东西(可能是在 go 增强它的链接器的时候)。
如果以前从未有过这样的讨论,那么 go 甚至 c 链接器是否可以通过任何方式查看我编译的二进制文件,并揭示一些我可以自己进一步解析的东西?

最佳答案

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

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

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 运行时的某些部分,但我猜这对您来说不是最重要的。

关于go - 如何检查链接到我的 Go 代码中的包的大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70764915/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com