如何确定为什么我的库中的文本大小如此之大?

How to determine why text size in my library is so huge?

我有一个使用 Android NDK for ARM 构建的共享库文件。那里也有一点 JNI。这个 SO 文件链接到许多其他 .a 文件(我们自己构建的静态库作为依赖项)以及一些其他第三方静态库,例如 boost。

我正在使用 GCC 4.8 并利用具有 C++11 功能的 STL。

我对此做了一些自我研究。特别是,我遇到了这个线程:
why my C++ output executable is so big?

这帮助我弄清楚了 运行 的一些命令,例如 size:

$ size libmine.so
   text    data     bss     dec     hex filename
13017993         201972   54120 13274085         ca8be5 libmine.so

不幸的是,除了 运行 的命令外,链接的 SO 问题在诊断方面对我没有太大帮助(或者也许我对 linux 的经验不足-风格发展以可靠地使用信息)。我不确定如何分析生成的结果,以帮助我查明导致任何增长的代码区域、特定库或模板 functions/classes/etc。

共享库本身有 13MB,相当大。我确实验证了我的 .SO 文件是 "stripped",我猜这意味着没有调试符号。在这一点上,我不确定这是由于提升还是一些疯狂的模板实例化。我如何确定是什么导致了我的共享库的大量增长?

I have no answers. Yet. Just sharing my quick & dirty oneliners so you don't have to. Disclaimer The performance is abysmal but GoodEnough™. Perl/Python/Haskell/... should have been used pragmatism was the keyword.

You need bc installed for the summations ¹

从 Andy Brown 的评论开始,我分析了我自己项目的二进制文件:

  • 定义一个辅助函数来列出名字:

    function names() { nm -l -S --size-sort --radix=d -C "$@"; }
    

    删除 -l(行号)以获得更好的性能(我不需要)

  • 以下单行重复显示累积大小:

    for a in bin/*; do echo -e "$a\t$(names "$a" | \
         cut -d\   -f1-2 | sort | uniq -cd | \
         perl -ne '@a=split and print "" . (($a[0]-1) * $a[2]) . "\n"' | \
         paste -sd+ | bc)"; done
    

    This tends to show only weak symbols. Because the actual values are duplicates here, I'm not sure this actually means the size in duplicates counts to the stripped binary file-size

  • 符号类型直方图:

    for a in bin/*; do names "$a" | awk '{print }'; done | sort | uniq -c | sort -rn
    
  • 按符号类型划分的符号总大小,按照上一步中直方图的频率降序排列:

    for a in bin/*; do names "$a" | awk '{print }'; done | \
        sort | uniq -c | sort -rn | \
        while read count type
        do 
            total=0
            for a in bin/*
            do 
                size=$(names "$a" | awk "$3==\"$type\" {print $2}" | paste -sd+ | bc)
                total=$(($total + $size))
                echo -e "$type\t$size\t$a"
            done
            echo -e "total:\t$total\ttotal bytes in $count symbols\n-------"
        done
    

我系统上的示例输出:

bin/tool1          208148
bin/liba.so        204463
bin/libcryptopp.so 166771
bin/tool2          211916
bin/tool3          204733
bin/testrunner     208271

46935   W
16173   V
10442   T
 1724   u
  574   d
  184   R
  158   B
   94   t
   49   r
   33   b
   13   D


W   1053961 bin/tool1
W   1030888 bin/liba.so
W   784518  bin/libcryptopp.so
W   1097729 bin/tool2
W   1031444 bin/tool3
W   1072752 bin/testrunner
total:  6071292 total bytes in 46935 symbols
-------
V   317146  bin/tool1
V   243869  bin/liba.so
V   368815  bin/libcryptopp.so
V   321841  bin/tool2
V   316629  bin/tool3
V   316947  bin/testrunner
total:  1885247 total bytes in 16173 symbols
-------
T   459075  bin/tool1
T   449020  bin/liba.so
T   610503  bin/libcryptopp.so
T   455224  bin/tool2
T   450630  bin/tool3
T   449234  bin/testrunner
total:  2873686 total bytes in 10442 symbols
-------
u   4912    bin/tool1
u   4136    bin/liba.so
u   448 bin/libcryptopp.so
u   5381    bin/tool2
u   4136    bin/tool3
u   4136    bin/testrunner
total:  23149   total bytes in 1724 symbols
-------

¹ 我知道它可以用纯 bash 来完成,但它要么涉及在评估扩展中扩展整个流,要么编写更多的嵌套循环。我更喜欢这里的 bc