golang.org/toolchain@v0.0.1-go1.9rc2.windows-amd64/blog/content/go1.7-binary-size.article (about)

     1  Smaller Go 1.7 binaries
     2  18 Aug 2016
     3  
     4  David Crawshaw
     5  crawshaw@golang.org
     6  
     7  * Introduction
     8  
     9  Go was designed for writing servers.
    10  That is how it is most widely used today, and as a result a lot of
    11  work on the runtime and compiler is focused on issues that matter to
    12  servers: latency, ease of deployment, precise garbage collection,
    13  fast startup time, performance.
    14  
    15  As Go gets used for a wider variety of programs, there are new issues that must be considered.
    16  One of these is binary size.
    17  It has been on the radar for a long time
    18  (issue [[https://golang.org/issue/6853][#6853]] was filed over two
    19  years ago), but the growing interest in using Go for
    20  deploying binaries on smaller devices — such as the Raspberry Pi or
    21  mobile devices — means it received some attention for the Go 1.7
    22  release.
    23  
    24  * Work done in Go 1.7
    25  
    26  Three significant changes in Go 1.7 affect binary size.
    27  
    28  The first is the new SSA backend that was enabled for AMD64 in this release.
    29  While the primary motivation for SSA was improved performance, the
    30  better generated code is also smaller.
    31  The SSA backend shrinks Go binaries by ~5%.
    32  We expect larger gains for the more RISC-like architectures
    33  like ARM and MIPS when those backends have been converted to SSA in Go 1.8.
    34  
    35  The second change is method pruning.
    36  Until 1.6, all methods on all used types were kept, even if some of
    37  the methods were never called.
    38  This is because they might be called through an interface, or called
    39  dynamically using the reflect package.
    40  Now the compiler discards any unexported methods that do not match an
    41  interface.
    42  Similarly the linker can discard other exported methods, those that are only
    43  accessible through reflection, if the corresponding
    44  [[https://golang.org/pkg/reflect/#Value.Call][reflection features]]
    45  are not used anywhere in the program.
    46  That change shrinks binaries by 5–20%.
    47  
    48  The third change is a more compact format for run-time type
    49  information used by the reflect package.
    50  The encoding format was originally designed to make the decoder in
    51  the runtime and reflect packages as simple as possible. By making this
    52  code a bit harder to read we can compress the format without affecting
    53  the run-time performance of Go programs.
    54  The new format shrinks Go binaries by a further 5–15%.
    55  Libraries built for Android and archives built for iOS shrink further
    56  as the new format contains fewer pointers, each of which requires
    57  dynamic relocations in position independent code.
    58  
    59  In addition, there were many small improvements such as improved
    60  interface data layout, better static data layout, and simplified
    61  dependencies. For example, the HTTP client no longer links in the entire HTTP
    62  server.
    63  The full list of changes can be found in issue
    64  [[https://golang.org/issue/6853][#6853]].
    65  
    66  * Results
    67  
    68  Typical programs, ranging from tiny toys to large production programs,
    69  are about 30% smaller when built with Go 1.7.
    70  
    71  The canonical hello world program goes from 2.3MB to 1.6MB:
    72  
    73  	package main
    74  
    75  	import "fmt"
    76  
    77  	func main() {
    78  		fmt.Println("Hello, World!")
    79  	}
    80  
    81  When compiled without debugging information the statically
    82  linked binary is now under a megabyte.
    83  
    84  .image go1.7-binary-size.png
    85  
    86  A large production program used for testing this cycle, `jujud`, went from 94MB
    87  to 67MB.
    88  
    89  Position-independent binaries are 50% smaller.
    90  
    91  In a position-independent executable (PIE), a pointer in a read-only
    92  data section requires a dynamic relocation.
    93  Because the new format for type information replaces pointers by
    94  section offsets, it saves 28 bytes per pointer.
    95  
    96  Position-independent executables with debugging information removed
    97  are particularly important to mobile developers, as this is the kind
    98  of program shipped to phones.
    99  Big downloads make for a poor user experience, so the reduction here
   100  is good news.
   101  
   102  * Future Work
   103  
   104  Several changes to the run-time type information were too late for the
   105  Go 1.7 freeze, but will hopefully make it into 1.8, further shrinking
   106  programs, especially position-independent ones.
   107  
   108  These changes are all conservative, reducing binary size without increasing
   109  build time, startup time, overall execution time, or memory usage.
   110  We could take more radical steps to reduce binary size: the
   111  [[http://upx.sourceforge.net/][upx]] tool for compressing executables
   112  shrinks binaries by another 50% at the cost of increased startup time
   113  and potentially increased memory use.
   114  For extremely small systems (the kind that might live on a keychain)
   115  we could build a version of Go without reflection, though it is
   116  unclear whether such a restricted language would be sufficiently
   117  useful.
   118  For some algorithms in the runtime we could use slower but more
   119  compact implementions when every kilobyte counts.
   120  All of these call for more research in later development cycles.
   121  
   122  To the many contributors who helped make Go 1.7 binaries smaller,
   123  thank you!