Go এর বিশাল আকারের সংকলন সম্পাদনের কারণ


90

আমি একটি হ্যালো ওয়ার্ল্ড গো প্রোগ্রামটি মেনে চললাম যা আমার লিনাক্স মেশিনে দেশীয় নির্বাহযোগ্য able তবে আমি হ্যালো ওয়ার্ল্ড গো প্রোগ্রামের আকারটি দেখে অবাক হয়েছি, এটি ছিল 1.9MB!

কেন এটি এত সহজ প্রোগ্রামের এক্সিকিউটেবল এত বিশাল?


22
বিপুল? আমার ধারণা আপনি তখন খুব বেশি জাভা করবেন না!
রিক -777

19
ভাল, আমি সি / সি ++ ব্যাকগ্রাউন্ড থেকে এসেছি!
কার্তিক রাও

আমি এই স্কেল -নেটিভ হ্যালো ওয়ার্ল্ডটি কেবল চেষ্টা করেছি: scala-native.org/en/latest/user/sbt.html#minimal-sbt-project কম্পাইল করতে বেশ কিছুটা সময় লেগেছে, প্রচুর স্টাফ ডাউনলোড হয়েছে এবং বাইনারিটি 3.9 এমবি
বিলি

আমি নীচে আমার উত্তরটি 2019 এর অনুসন্ধানের সাথে আপডেট করেছি
ভোনসি

4
সি # .NET কোর 3.1 সহ সাধারণ হ্যালো ওয়ার্ল্ড অ্যাপ্লিকেশনটি dotnet publish -r win-x64 -p:publishsinglefile=true -p:publishreadytorun=true -p:publishtrimmed=trueপ্রায় M 26MB এর একটি বাইনারি ফাইল উত্পন্ন করে!
জালাল

উত্তর:


90

এই সঠিক প্রশ্নটি অফিসিয়াল এফএকিউতে উপস্থিত হয়: আমার তুচ্ছ প্রোগ্রামটি এত বড় বাইনারি কেন?

উত্তরটি উদ্ধৃত করে:

জিসি টুল শৃঙ্খল (ইন linkers 5l, 6lএবং 8l) স্ট্যাটিক লিঙ্ক না। সমস্ত গোটা বাইনারিগুলির মধ্যে ডায়নামিক ধরণের চেক, প্রতিবিম্ব এবং এমনকি প্যানিক-টাইম স্ট্যাক ট্রেস সমর্থন করার জন্য প্রয়োজনীয় রান-টাইম তথ্যের পাশাপাশি গো রান-টাইম অন্তর্ভুক্ত থাকে।

একটি সাধারণ সি "হ্যালো, ওয়ার্ল্ড" প্রোগ্রামটি লিনাক্সে জিসিসি ব্যবহার করে স্ট্যাটিক্যালি সংকলিত এবং সংযুক্ত এবং এর বাস্তবায়ন সহ প্রায় 750 কেবি হয় printf। সমতুল্য গো প্রোগ্রামটি fmt.Printfপ্রায় 1.9 মেগাবাইটের কাছাকাছি হয় তবে এতে আরও শক্তিশালী রান-টাইম সমর্থন এবং টাইপ তথ্য অন্তর্ভুক্ত রয়েছে।

সুতরাং আপনার হ্যালো ওয়ার্ল্ডের নেটিভ এক্সিকিউটেবল 1.9 এমবি কারণ এটিতে রানটাইম রয়েছে যা আবর্জনা সংগ্রহ, প্রতিচ্ছবি এবং অন্যান্য অনেকগুলি বৈশিষ্ট্য সরবরাহ করে (যা আপনার প্রোগ্রামটি সম্ভবত ব্যবহার না করে তবে এটি সেখানে রয়েছে)। এবং fmtআপনি যে প্যাকেজটি প্রবন্ধটি মুদ্রণ করতে ব্যবহার করেছিলেন তার বাস্তবায়ন "Hello World"(প্লাস এর নির্ভরতা)।

এখন নিম্নলিখিতটি ব্যবহার করে দেখুন: fmt.Println("Hello World! Again")আপনার প্রোগ্রামে আরও একটি লাইন যুক্ত করুন এবং এটি আবার সংকলন করুন। ফলাফলটি 2x 1.9MB হবে না, তবে এখনও মাত্র 1.9 মেগাবাইট! হ্যাঁ, কারণ ব্যবহৃত সমস্ত লাইব্রেরি ( fmtএবং এর নির্ভরতা) এবং রানটাইম ইতিমধ্যে এক্সিকিউটেবলের সাথে যুক্ত করা হয়েছে (এবং তাই আপনি কেবল যুক্ত করেছেন এমন দ্বিতীয় পাঠ্য মুদ্রণের জন্য আরও কয়েকটি বাইট যুক্ত করা হবে)।


10
এসি "হ্যালো ওয়ার্ল্ড" প্রোগ্রাম, গ্লোবিকের সাথে স্থিতিশীলভাবে যুক্ত 750 কে কারণ গ্লিবসিটি স্পষ্টতই স্ট্যাটিক লিঙ্কিংয়ের জন্য ডিজাইন করা হয়নি এবং কিছু ক্ষেত্রে সঠিকভাবে স্থির লিঙ্কটি পাওয়া অসম্ভব। একটি "হ্যালো ওয়ার্ল্ড" প্রোগ্রামটি স্থিরভাবে ম্যাসল লিবিসি-র সাথে যুক্ত 14
ক্রেগ বার্নস

তবে আমি এখনও খুঁজছি, এটির সাথে কী যুক্ত রয়েছে তা জেনে ভাল লাগবে যাতে সম্ভবত কোনও আক্রমণকারী দুষ্ট কোডে লিঙ্ক না করে।
রিচার্ড 13

তাহলে কেন কোনও ডিএলএল ফাইলের গো রানটাইম লাইব্রেরি নেই, যাতে এটি সমস্ত গো এক্সি ফাইলগুলির মধ্যে ভাগ করা যায়? তারপরে একটি "হ্যালো ওয়ার্ল্ড" প্রোগ্রামটি 2 মেগাবাইটের পরিবর্তে প্রত্যাশা অনুযায়ী কয়েক কেবি হতে পারে। প্রতিটি প্রোগ্রামে পুরো রানটাইম লাইব্রেরিটি উইন্ডোতে এমএসভিসির অন্যথায় দুর্দান্ত বিকল্পের জন্য মারাত্মক ত্রুটি।
ডেভিড স্পেক্টর

আমি আমার মন্তব্যে কোনও আপত্তিটি আরও ভালভাবে অনুমান করতে পারি: যে গো "স্ট্যাটিকালি লিঙ্কড"। ঠিক আছে, তখন কোনও ডিএলএল নেই। তবে স্ট্যাটিক লিঙ্কিংয়ের অর্থ এই নয় যে আপনাকে একটি সম্পূর্ণ লাইব্রেরি (বাঁধাই) করতে হবে, কেবলমাত্র ফাংশন যা লাইব্রেরিতে ব্যবহৃত হয়!
ডেভিড স্পেক্টর

44

নিম্নলিখিত প্রোগ্রাম বিবেচনা করুন:

package main

import "fmt"

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

যদি আমি এটি আমার লিনাক্স এএমডি 64 মেশিনে (Go 1.9) তৈরি করি তবে:

$ go build
$ ls -la helloworld
-rwxr-xr-x 1 janf group 2029206 Sep 11 16:58 helloworld

আমি এআ বাইনারি পাই যা প্রায় 2 এমবি আকারের।

এর কারণ (যা অন্যান্য উত্তরে ব্যাখ্যা করা হয়েছে) হ'ল আমরা "এফএমটি" প্যাকেজটি ব্যবহার করছি যা বেশ বড়, তবে বাইনারিটিও ছিনিয়ে নেওয়া হয়নি এবং এর অর্থ প্রতীক টেবিলটি এখনও আছে। আমরা যদি পরিবর্তে বাইনারি ফালা করতে কম্পাইলারকে নির্দেশ করি তবে এটি অনেক ছোট হয়ে যাবে:

$ go build -ldflags "-s -w"
$ ls -la helloworld
-rwxr-xr-x 1 janf group 1323616 Sep 11 17:01 helloworld

তবে, আমরা যদি এফএমটি.প্রিন্টলন এর পরিবর্তে বিল্টিন ফাংশন মুদ্রণটি ব্যবহার করার জন্য প্রোগ্রামটি পুনরায় লিখন করি:

package main

func main() {
    print("Hello World!\n")
}

এবং তারপরে এটি সংকলন করুন:

$ go build -ldflags "-s -w"
$ ls -la helloworld
-rwxr-xr-x 1 janf group 714176 Sep 11 17:06 helloworld

আমরা একটি এমনকি আরও ছোট বাইনারি সঙ্গে শেষ। এটি যতটা ছোট আমরা ইউপিএক্স-প্যাকিংয়ের মতো কৌশল অবলম্বন না করে এটি পেতে পারি, তাই গো-রানটাইমের ওভারহেড প্রায় 700 কেবি হয়।


4
ইউপিএক্স বাইনারিগুলি সংকুচিত করে এবং যখন তারা কার্যকর করা হয় তখন তাদেরকে ফ্লাইটটি অন-দ্য ড্রেপ্রেস করে। এটি কী করে তা ব্যাখ্যা না করেই আমি এটিকে কোনও কৌশল বরখাস্ত করব না, যেহেতু এটি কিছু পরিস্থিতিতে কার্যকর হতে পারে। প্রারম্ভকালীন সময় এবং র‌্যাম ব্যবহার ব্যয়ে বাইনারি আকার কিছুটা হ্রাস করা হয়; তদ্ব্যতীত, কর্মক্ষমতা পাশাপাশি সামান্য প্রভাবিত হতে পারে। যেমন একটি উদাহরণ হিসাবে, একটি এক্সিকিউটেবল তার (স্ট্রাইপড) আকারের 30% থেকে সঙ্কুচিত হতে পারে এবং চালাতে 35 মিমি বেশি সময় নেয়।
সিমলেভ করুন

10

লক্ষ্য করুন বাইনারি আকার ইস্যু দ্বারা ট্র্যাক করা হয় ইস্যু 6853 সালে golang / Go প্রকল্পের

উদাহরণস্বরূপ, a26c01a (Go 1.4 এর জন্য) প্রতিশ্রুতিবদ্ধ হ্যালো ওয়ার্ল্ডকে 70 কেবি দ্বারা কাটা :

কারণ আমরা সেই নামগুলি প্রতীক টেবিলটিতে লিখি না।

সংকলক, এসেম্বলার, লিঙ্কার এবং 1.5 এর রানটাইম বিবেচনা করে পুরোপুরি গোতে থাকবে, আপনি আরও অপ্টিমাইজেশন আশা করতে পারেন।


২০১ 2016 Go 1.7 আপডেট করুন: এটি অনুকূলিত করা হয়েছে: " ছোট যান 1.7 বাইনারি " দেখুন।

তবে এই দিনটি (এপ্রিল 2019), সবচেয়ে বেশি জায়গা নেয় runtime.pclntab
দেখুন " আমার যান এক্সিকিউটেবল ফাইলের তাই যান বৃহৎ? সাইজ কল্পনা থেকে D3 ব্যবহার এক্সেকিউটেবল কেন থেকে" রাফায়েল 'kena' Poss

এটি খুব ভাল নথিবদ্ধ নয় তবে গো উত্স কোড থেকে এই মন্তব্যটি এর উদ্দেশ্যটির পরামর্শ দেয়:

// A LineTable is a data structure mapping program counters to line numbers.

এই ডেটা স্ট্রাকচারের উদ্দেশ্য হ'ল রান রানটাইম সিস্টেমটিকে ক্র্যাশের সময় বা runtime.GetStackAPI এর মাধ্যমে অভ্যন্তরীণ অনুরোধের ভিত্তিতে বর্ণনামূলক স্ট্যাকের ট্রেস তৈরি করতে সক্ষম করা ।

সুতরাং এটি দরকারী মনে হয়। তবে এত বড় কেন?

উপরের লিঙ্কযুক্ত উত্স ফাইলটিতে লুকানো https://golang.org/s/go12symtab URL একটি নথিতে পুনঃনির্দেশ করে যা Go 1.0 এবং 1.2 এর মধ্যে কী ঘটেছিল তা ব্যাখ্যা করে। প্যারাফ্রেজ করতে:

1.2 এর আগে, গো লিঙ্কার একটি সংকুচিত লাইন টেবিল নির্গত করছিল, এবং প্রোগ্রামটি রান-টাইমে সূচনা করার সময় এটি সঙ্কুচিত করবে।

Go 1.2 এ, এক্সিকিউটেবল ফাইলের লাইন টেবিলটিকে পূর্ব-প্রসারিত করার জন্য সিদ্ধান্ত নেওয়া হয়েছিল এটির চূড়ান্ত বিন্যাসে রান-টাইমে সরাসরি ব্যবহারের জন্য উপযুক্ত, কোনও অতিরিক্ত সংক্ষেপণ পদক্ষেপ ছাড়াই।

অন্য কথায়, গো দল প্রাথমিককরণের সময় সংরক্ষণের জন্য এক্সিকিউটেবল ফাইলগুলি আরও বড় করার সিদ্ধান্ত নিয়েছে।

এছাড়াও, ডাটা স্ট্রাকচারের দিকে তাকালে, এটি প্রদর্শিত হয় যে সংকলিত বাইনারিগুলিতে এর সামগ্রিক আকারটি প্রতিটি ফাংশনটি কত বড় সেগুলি ছাড়াও প্রোগ্রামের ফাংশনের সংখ্যার তুলনায় সুপার-লিনিয়ার।

https://sज्ञान.raphael.poss.name/go-executable-size-visualization-with-d3/size-demo-ss.png


4
আমি দেখতে পাচ্ছি না যে তিনি বাস্তবায়নের ভাষাটির সাথে এর কী সম্পর্ক রয়েছে। তাদের ভাগ করা লাইব্রেরি ব্যবহার করা দরকার। কিছুটা অবিশ্বাস্য যে তারা এই দিন এবং যুগে ইতিমধ্যে নেই।
লার্নের মারকুইস

4
@ এজেপি: তাদের কেন ভাগ করা লাইব্রেরি ব্যবহার করা দরকার?
ফ্লিমজি

9
@ ইজেপি, গো-এর সরলতার অংশ ভাগ করা লাইব্রেরি ব্যবহার না করা। আসলে, গো এর কোনও নির্ভরতা নেই, এটি প্লেইন সিস্কলগুলি ব্যবহার করে। কেবল একটি একক বাইনারি স্থাপন করুন এবং এটি ঠিক কাজ করে। এটি ভাষাটিকে উল্লেখযোগ্যভাবে ক্ষতি করবে এবং এটি অন্যথায় হলে এটি বাস্তুসংস্থান।
নির্মাতা 15

10
স্ট্যাটিকালি লিঙ্কযুক্ত বাইনারি থাকার একটি প্রায়শই ভুলে যাওয়া দিকটি হ'ল এটি একটি সম্পূর্ণ ফাঁকা ডকার-ধারক মধ্যে চালানো সম্ভব করে তোলে। সুরক্ষার দিক থেকে এটি আদর্শ। যখন ধারকটি খালি থাকে, আপনি সম্ভবত ভাঙ্গতে সক্ষম হবেন (যদি স্ট্যাটিকালি লিঙ্কযুক্ত বাইনারিগুলির ত্রুটি থাকে) তবে যেহেতু ধারকটিতে কিছুই খুঁজে পাওয়া যায়নি, আক্রমণটি সেখানেই থামে।
জোপ্পে
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.