संकलित फ़ाइल का आकार कैसे कम करें?


84

चलो सी की तुलना करें और जाएं: Hello_world.c:

#include<stdio.h>
int main(){
    printf("Hello world!");
}

Hello_world.go:

package main
import "fmt"
func main(){
    fmt.Printf("Hello world!")
}

दोनों को संकलित करें:

$gcc Hello_world.c -o Hello_c 
$8g Hello_world.go -o Hello_go.8
$8l Hello_go.8 -o Hello_go

और वो क्या है?

$ls -ls
... 5,4K 2010-10-05 11:09 Hello_c
... 991K 2010-10-05 11:17 Hello_go

1Mb हैलो दुनिया के बारे में। क्या आप मेरे साथ मजाक कर रहे हैं? मैं क्या गलत करूँ?

(पट्टी Hello_go -> 893K केवल)


2
एक x86_64 मैक पर "हैलो वर्ल्ड" बाइनरी 1.3 एमबी है जैसे कि एक x64 लिनक्स मशीन पर मैं मानता हूं। इसके विपरीत ARM x32 बाइनरी x86_32 बाइनरी जितना बड़ा है। आकार महत्वपूर्ण रूप से संबंधित वास्तुकला की "शब्द" लंबाई पर निर्भर करता है। X32 मशीनों पर यह 32 बिट है x64 पर यह 64 बिट चौड़ा है। इसलिए x32 "हैलो वर्ल्ड" बाइनरी लगभग 30% छोटा है।
एलेक्स

17
@ निक: यह देखते हुए कि GO को एक सिस्टम भाषा के रूप में विपणन किया जाता है, मुझे लगता है कि यह एक उचित प्रश्न है। मैं सिस्टम में काम करता हूं और हमारे पास हमेशा 4 जीबी + रैम और एक विशाल डिस्क की लक्जरी नहीं होती है।
एड एस।

3
एक 893kb निष्पादन योग्य "4 जीबी + रैम और एक विशाल डिस्क" से बहुत दूर रोना है, और जैसा कि अन्य ने पहले ही बताया है, इसमें स्टेटिकली लिंक्ड गो रनटाइम शामिल है, जिसे आसानी से बाहर रखा जा सकता है।
निक जॉनसन

22
हाँ, यह बहुत दूर का रोना है, और मुझे इसका उत्तर पता है, लेकिन यह एक वैध प्रश्न है और "जो स्मृति की खपत के बारे में परवाह करता है, वह उन प्रणालियों पर काम करने से रोकता है जहां यह कोई फर्क नहीं पड़ता है। आपको लगता है कि अज्ञानता है। यह ठीक है और यह बेहतर है कि आप सवाल न पूछें। और मैं फिर से कहूंगा; कभी-कभी ~ 1MB बहुत कुछ होता है, आप स्पष्ट रूप से उस दुनिया में नहीं हैं। EDIT - आप Google में काम करते हैं! lol। मैं अभी भी नहीं मिलता। हालांकि, 'कौन परवाह करता है'
एड एस।

12
जावा विभाग में जाहिर है;)
मैट जॉइनर

जवाबों:


29

क्या यह समस्या है कि फ़ाइल बड़ी है? मुझे नहीं पता, लेकिन मुझे लगता है कि यह सांख्यिकीय रूप से कुछ रनटाइम लिबास को लिंक करेगा जो कि सी प्रोग्राम के लिए नहीं है। लेकिन शायद इस बात की चिंता नहीं है कि जैसे ही आपका कार्यक्रम बड़ा होगा।

जैसा कि यहाँ बताया गया है , गो रनटाइम को स्टेटिकली लिंक करना डिफ़ॉल्ट है। यह पृष्ठ आपको गतिशील लिंकिंग के लिए सेट अप करने का तरीका भी बताता है।


2
एक खुला मुद्दा है , जिसमें Go1.5 के लिए मील का पत्थर सेट है
जो

79

यदि आप यूनिक्स-आधारित प्रणाली (जैसे लिनक्स या मैक ओएसएक्स) का उपयोग कर रहे हैं, तो आप -w फ्लैग के साथ इसे बनाकर निष्पादन योग्य में शामिल डिबगिंग जानकारी को हटाने का प्रयास कर सकते हैं:

go build -ldflags "-w" prog.go

फ़ाइल का आकार नाटकीय रूप से कम हो जाता है।

अधिक जानकारी के लिए GDB के पृष्ठ पर जाएँ: http://golang.org/doc/gdb


3
वही stripकमांड के साथ प्राप्त किया जाता है : go build prog.go; strip progतब हमें तथाकथित धारीदार निष्पादन योग्य मिला : ELF 64-बिट एलएसबी निष्पादन योग्य, x86-64, संस्करण 1 (SYSV), गतिशील रूप से जुड़ा हुआ (साझा libs का उपयोग करता है), छीन लिया गया
अलेक्जेंडर I.Govov

1
यह विंडोज पर काम करता है, और सामान्य रूप से निर्माण और स्ट्रिपिंग द्वारा उत्पादित की तुलना में थोड़ी छोटी बाइनरी फ़ाइल प्रदान करता है।
इस्केक

9
@ एक्सल: स्ट्रिपिंग गो बायनेरिज़ स्पष्ट रूप से समर्थित नहीं है, और कुछ मामलों में गंभीर कीड़े पैदा कर सकता है। देखें यहाँ
टिमटिमा

9
वर्तमान में -w, इसके बजाय दस्तावेज़ीकरण सूची -s। यह निश्चित नहीं है कि अंतर क्या है, लेकिन आप अपने उत्तर को अपडेट करना चाह सकते हैं :-)
डायनाम

2
@ डायनोम: -वह आकार को कुछ कम करता दिख रहा है लेकिन कमी -s के साथ उतनी अच्छी नहीं है। -s प्रतीत होता है -w: golang.org/cmd/link
Arkod

42

2016 का जवाब:

1. प्रयोग करें 1.7

2. के साथ संकलन go build -ldflags "-s -w"

➜ ls -lh hello
-rwxr-xr-x 1 oneofone oneofone 976K May 26 20:49 hello*

3. फिर उपयोग करें upx, goupxअब 1.6 की जरूरत नहीं है।

➜ ls -lh hello
-rwxr-xr-x 1 oneofone oneofone 367K May 26 20:49 hello*

3
मैं यहाँ जोड़ना चाहूंगा कि यूपीएक्स के बारे में आम तौर पर केवेट शायद यहाँ लागू होते हैं। अधिक जानकारी के लिए इसे देखें: stackoverflow.com/questions/353634/… (इसका अधिकांश भाग गैर-विंडोज ऑपरेटिंग सिस्टम पर भी लागू होता है)।
जोनास

23

गो बायनेरिज़ बड़े हैं क्योंकि वे सांख्यिकीय रूप से जुड़े हुए हैं (कोगो का उपयोग करते हुए लाइब्रेरी बाइंडिंग को छोड़कर)। सी प्रोग्राम को स्टेटिकली लिंक करने का प्रयास करें और आप देखेंगे कि यह एक तुलनीय आकार में विकसित होगा।

यदि यह वास्तव में आपके लिए एक समस्या है (जिस पर मुझे विश्वास करना कठिन है), तो आप gccgo और गतिशील रूप से लिंक के साथ संकलन कर सकते हैं।


19
इसके अलावा यह एक ऐसी भाषा के लिए एक अच्छा कदम है जो अभी तक सार्वभौमिक रूप से नहीं अपनाया गया है। किसी को भी अपने सिस्टम को अव्यवस्थित तरीके से चलाने की दिलचस्पी नहीं है।
मैट जॉइनर

4
गो निर्माता स्पष्ट रूप से गतिशील लिंकिंग पसंद करते हैं: हानिकारक . cat-v.org/software/dynamic-linking । Google सांख्यिकीय रूप से अपने सभी C और C ++: reddit.com/r/golang/comments/tqudb/…
ग्राहम किंग

14
मुझे लगता है कि जुड़ा हुआ लेख विपरीत बताता है - गो निर्माता स्पष्ट रूप से स्थैतिक लिंकिंग पसंद करते हैं।
पेटर डोनचेव

16

आपको goupx मिलना चाहिए , यह काम करने के लिए गोलंग ईएलएफ निष्पादनयोग्य को "ठीक" करेगा upx। मुझे पहले से ही कुछ मामलों में लगभग 78% फ़ाइल आकार सिकुड़ गया है ~16MB >> ~3MB

संपीड़न अनुपात आमतौर पर 25% हो जाता है, इसलिए यह एक कोशिश के लायक है:

$ go get github.com/pwaller/goupx
$ go build -o filename
$ goupx filename

>>

2014/12/25 10:10:54 File fixed!

        File size         Ratio      Format      Name
   --------------------   ------   -----------   -----------
  16271132 ->   3647116   22.41%  linux/ElfAMD   filename                            

Packed 1 file.

अतिरिक्त: -sझंडा (पट्टी) बिन फ़ाइल को और भी अधिक सिकोड़ सकता हैgoupx -s filename


1
यह उत्कृष्ट है, धन्यवाद! मैं GOARCH = 386 सेट कर रहा हूं और अभी कुछ समय के लिए सामान्य अपैक्स का उपयोग कर रहा हूं।
कोडकोला

10
यह अब गो 1.6 के रूप में आवश्यक नहीं है, आप सामान्य अपैक्स का उपयोग कर सकते हैं।
OneOfOne

11

नाम की एक फ़ाइल बनाएं main.go, चलो सरल हैलो वर्ल्ड प्रोग्राम के साथ प्रयास करें।

package main

import "fmt"

func main(){
    fmt.Println("Hello World!")
}

मैं 1.9.1 संस्करण का उपयोग करता हूं

$ go version
 go version go1.9.1 linux/amd64

मानक go buildकमांड के साथ संकलित करें ।

$ go build main.go
$ ls -lh
-rwxr-xr-x-x 1 nil nil 1.8M Oct 27 07:47 main

आइए एक बार फिर से संकलित करें go buildलेकिन ldflagsजैसा कि ऊपर बताया गया है,

$ go build -ldflags "-s -w" main.go
$ ls -lh
-rwxr-xr-x-x 1 nil nil 1.2M Oct 27 08:15 main

फ़ाइल का आकार 30% तक कम हो जाता है।

अब, उपयोग करने देता है gccgo,

$ go version
 go version go1.8.1 gccgo (GCC) 7.2.0 linux/amd64

बिल्डिंग के साथ जाना gccgo,

$ go build main.go
$ ls -lh
-rwxr-xr-x 1 nil nil 34K Oct 27 12:18 main

बाइनरी आकार लगभग 100% कम हो गया है। के एक बार फिर से हमारे निर्माण की कोशिश करते हैं main.goके साथ gccgo, लेकिन निर्माण झंडे के साथ,

$ go build -gccgoflags "-s -w" main.go
-rwxr-xr-x 1 nil nil 23K Oct 27 13:02 main

चेतावनी: चूंकि gccgoबायनेरिज़ गतिशील रूप से जुड़े हुए थे। यदि आपके पास एक बाइनरी है जो आकार में बहुत बड़ा है, तो gccgo के साथ संकलित होने पर आपका बाइनरी 100% से कम नहीं होगा, लेकिन यह आकार में काफी कम हो जाएगा।

जीसी की तुलना में, gccgo कोड संकलित करने के लिए धीमा है, लेकिन अधिक शक्तिशाली अनुकूलन का समर्थन करता है, इसलिए gccgo द्वारा निर्मित सीपीयू-बाउंड प्रोग्राम आमतौर पर तेजी से चलेगा। इन वर्षों में जीसीसी में कार्यान्वित सभी अनुकूलन उपलब्ध हैं, जिनमें इनलाइनिंग, लूप ऑप्टिमाइज़ेशन, वैश्वीकरण, अनुदेश निर्धारण, और बहुत कुछ शामिल हैं। हालांकि यह हमेशा बेहतर कोड का उत्पादन नहीं करता है, कुछ मामलों में gccgo के साथ संकलित कार्यक्रम 30% तेजी से चल सकते हैं।

जीसीसी 7 रिलीज में गो 1.8 उपयोगकर्ता पुस्तकालयों के पूर्ण कार्यान्वयन को शामिल करने की उम्मीद है। पहले रिलीज के साथ, गो 1.8 रनटाइम पूरी तरह से विलय नहीं हुआ है, लेकिन यह गो कार्यक्रमों के लिए दिखाई नहीं देना चाहिए।

पेशेवरों:

  1. कम आकार का
  2. अनुकूलित।

विपक्ष

  1. धीरे
  2. के नवीनतम संस्करण का उपयोग नहीं कर सकते go

आप यहाँ और यहाँ देख सकते हैं ।


धन्यवाद। मेरे पास एक प्रश्न है, जैसा कि मैंने पढ़ा है, gogccएआरएम प्रोसेसर का समर्थन नहीं करता है, क्या यह सही है? और, क्या आप एक उपकरण का सुझाव दे सकते हैं जो गोलंग बिल्ड फ़ाइल आकार को कम करता है?
एम। रोस्तमी

1
आप कैसे gccgo के साथ संकलन करते हैं?
विटाली ज़डेनविच

10

अधिक कॉम्पैक्ट हैलो-विश्व उदाहरण:

package main

func main() {
  print("Hello world!")
}

हमें बड़े fmtपैकेज और सीधे तौर पर कम किए गए बाइनरी को छोड़ दिया जाता है:

  $ go build hello.go
  $ ls -lh hello
  ... 259K ... hello2
  $ strip hello
  $ ls -lh hello
  ... 162K ... hello2

C के रूप में इतना कॉम्पैक्ट नहीं है, लेकिन K नहीं M :) Ok में मापा जाता है, लेकिन यह सामान्य तरीका नहीं है बस एक आकार को अनुकूलित करने के कुछ तरीके दिखाता है: स्ट्रिप का उपयोग करें और न्यूनतम पैकेज का उपयोग करने का प्रयास करें। वैसे भी गो छोटे आकार की बायनेरी बनाने के लिए भाषा नहीं है।


11
यह कोड अंतर्निहित प्रिंट () फ़ंक्शन का उपयोग करता है और इस अभ्यास की अनुशंसा नहीं की जाती है। और सवाल यह नहीं था कि प्रदान किए गए नमूना कार्यक्रम के कोड आकार को कैसे कम किया जाए, बल्कि अधिक सामान्य तरीके से।
वाट्सएप

@wldsvc मैं आपसे सहमत हूं। हालांकि यह समझ में नहीं आता कि डिस्प्ले आउटपुट के लिए प्रिंट () खराब तरीका क्यों है? सरल स्क्रिप्ट के लिए या डिबग आउटपुट के लिए यह काफी अच्छा है।
अलेक्जेंडर I. ग्रेफोव

3
देखें doc.golang.org/ref/spec#Bootstrapping ये कार्य पूर्णता के लिए प्रलेखित हैं, लेकिन भाषा में बने रहने की गारंटी नहीं हैं । मेरे लिए इसका मतलब है कि एक समय डिबगिंग उद्देश्यों को छोड़कर किसी भी स्क्रिप्ट में "उनका उपयोग न करें"।
वौर्सविले

2020 में @worldvc प्रिंट () अभी भी मौजूद है लेकिन उसी अस्वीकरण के साथ
फनी ऋत्विज

3

आप इस विषय पर मेरे छोटे शोध को देख सकते हैं: https://github.com/xaionaro/documentation/blob/master/golang/reduce-binary-size.md

यह चरण-दर-चरण दिखाता है कि 2MiB हैलो-वर्ल्ड स्टैटिक-बाइनरी सैंपल को 15KiB स्टेटिक-बाइनरी या 10KiB डायनेमिक-बाइनरी में कैसे कम किया जाए। बेशक सीमाएँ बहुत हैं।


2

ब्रैड फिट्ज़पैट्रिक (मध्य जून 2018) द्वारा ट्वीट किए गए अगले गो 1.11 के लिए 2018 का जवाब :

कुछ मिनट पहले तक, # गोलोल ईएलएफ बायनेरिज़ में DWARF सेक्शन अब संकुचित हो गए हैं, इसलिए टिप बायनेरीज़ गो 1.10 से छोटे हैं, यहां तक ​​कि टिप पर सभी अतिरिक्त डिबग सामान भी हैं।

https://pbs.twimg.com/media/DfwkBaqUEAAb8-Q.jpg:large

सी एफ गोलंग अंक 11799 :

हमारे डिबग जानकारी को संपीड़ित करना एक महत्वपूर्ण, सस्ते फ़ाइल आकार की जीत की पेशकश कर सकता है।

प्रतिबद्ध 594eae5 में और देखें

cmd / लिंक: ELF बायनेरिज़ में DWARF सेक्शन को सेक करें

इसका सबसे पेचीदा हिस्सा यह है कि बाइनरी लेआउट कोड (blk, elfshbits, और विभिन्न अन्य चीजें) प्रतीकों के बीच एक निरंतर ऑफसेट मानती हैं 'और वर्गों के फ़ाइल स्थान और उनके वर्चुअल पते।

संपीड़न, ज़ाहिर है, इस निरंतर ऑफसेट को तोड़ता है।
लेकिन हमें संपीड़न से पहले रिलोकेशन को हल करने के लिए कंप्रेशन से पहले हर चीज को वर्चुअल एड्रेस असाइन करना होगा।

नतीजतन, संपीड़न को अपने संकुचित आकार के आधार पर DWARF वर्गों और प्रतीकों के "पते" को फिर से गणना करने की आवश्यकता होती है।
सौभाग्य से, ये फ़ाइल के अंत में हैं, इसलिए यह किसी भी अन्य अनुभाग या प्रतीकों को प्रभावित नहीं करता है। (और, ज़ाहिर है, DWARF सेगमेंट को मानने वाली कोड की एक आश्चर्यजनक राशि पिछले आती है, तो एक और जगह क्या है?)

name        old exe-bytes   new exe-bytes   delta
HelloSize      1.60MB ± 0%     1.05MB ± 0%  -34.39%  (p=0.000 n=30+30)
CmdGoSize      16.5MB ± 0%     11.3MB ± 0%  -31.76%  (p=0.000 n=30+30)
[Geo mean]     5.14MB          3.44MB       -33.08%

रोब पाइक उल्लेख :

यह केवल उन मशीनों पर मदद करता है जो ईएलएफ का उपयोग करते हैं।
बायनेरिज़ अभी भी बहुत बड़े हैं, और बढ़ रहे हैं।

ब्रैड ने जवाब दिया:

कम से कम यह कुछ तो है। बहुत बुरा होने वाला था।
एक रिलीज के लिए खून बह रहा रोक दिया।

कारण : जानकारी डीबग करें, लेकिन किसी निर्देश को सेव करने के लिए GC के लिए मानचित्र भी पंजीकृत करें।


2

डिफ़ॉल्ट रूप से gcc लिंक गतिशील रूप से और जाने - सांख्यिकीय रूप से।

लेकिन अगर आप सी कोड को सांख्यिकीय रूप से जोड़ते हैं, तो आपको बड़े आकार के साथ एक बाइनरी मिल सकती है।

मेरे मामले में:

  • go x64 (1.10.3) - 1214208 बाइट के साथ उत्पन्न बाइनरी
  • gcc x64 (6.2.0) - 1421312 बाइट के साथ बाइनरी जनरेट किया गया

दोनों बायनेरिज़ सांख्यिकीय रूप से जुड़े हुए हैं और बिना debug_info के हैं।

go build -ldflags="-s -w" -o test-go test.go
gcc -static -s -o test-c test.c

1

बाइनरी में डिफ़ॉल्ट रूप से कचरा संग्रहकर्ता, शेड्यूलिंग सिस्टम होता है जो गो रूटीन और आपके द्वारा आयात किए जाने वाले सभी पुस्तकालयों का प्रबंधन करता है।

परिणाम लगभग 1 एमबी का न्यूनतम आकार है।


1

Go 1.8 से, आप अपने बाइनरी को साझा पुस्तकालयों के समान कुछ में विभाजित करने के लिए नए प्लगइन सिस्टम का उपयोग कर सकते हैं। इस रिलीज के लिए यह केवल लिनक्स पर काम करता है, लेकिन भविष्य में अन्य प्लेटफार्मों का समर्थन किया जाएगा।

https://tip.golang.org/pkg/plugin/

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.