স্টে স্ট্রেস বনাম হিপ বরাদ্দগুলি এবং এগুলি কীভাবে আবর্জনা সংগ্রহের সাথে সম্পর্কিত rela


165

আমি যেতে নতুন এবং আমি সি স্টাইলের স্ট্যাক-ভিত্তিক প্রোগ্রামিংয়ের মধ্যে কিছুটা কংগ্রেসীয় বিচ্ছিন্নতা অনুভব করছি যেখানে স্বয়ংক্রিয় ভেরিয়েবলগুলি স্ট্যাকের উপরে বাস করে এবং গিরির উপরে পাইথন স্টাইলের স্ট্যাক-ভিত্তিক-প্রোগ্রামিং যেখানে বরাদ্দ থাকে স্ট্যাকের মধ্যে যে জিনিসটি থাকে কেবল তা হ'ল স্তরের বস্তুর উল্লেখ / পয়েন্টার।

আমি যতদূর বলতে পারি, নিম্নলিখিত দুটি ফাংশন একই আউটপুট দেয়:

func myFunction() (*MyStructType, error) {
    var chunk *MyStructType = new(HeaderChunk)

    ...

    return chunk, nil
}


func myFunction() (*MyStructType, error) {
    var chunk MyStructType

    ...

    return &chunk, nil
}

অর্থাত্ একটি নতুন কাঠামো বরাদ্দ করুন এবং এটি ফিরিয়ে দিন।

আমি যদি সিটিতে লিখতাম তবে প্রথমটি একটি গাদাতে একটি বস্তু রেখে দিত এবং দ্বিতীয়টি স্ট্যাকের উপরে রাখত। প্রথমটি স্তূপে একটি পয়েন্টার ফেরত দেবে, দ্বিতীয়টি স্ট্যাকের দিকে একটি পয়েন্টার ফিরিয়ে দেবে, যা ফাংশনটি ফিরে আসার সময় বাষ্পীভূত হয়ে উঠত, এটি একটি খারাপ জিনিস হবে।

আমি যদি পাইথনে এটি লিখতাম (বা সি # ব্যতীত আরও অনেক আধুনিক ভাষায়) উদাহরণ 2 সম্ভব হত না।

আমি পেয়েছি যে গো আবর্জনা উভয় মান সংগ্রহ করে, তাই উপরের দুটি ফর্মই ভাল।

উদ্ধৃতি থেকে:

দ্রষ্টব্য, সি থেকে পৃথক, স্থানীয় ভেরিয়েবলের ঠিকানা ফেরত দেওয়া পুরোপুরি ঠিক আছে; ভেরিয়েবলের সাথে সম্পর্কিত স্টোরেজটি ফাংশন ফিরে আসার পরে বেঁচে থাকে। প্রকৃতপক্ষে, যৌগিক আক্ষরিকের ঠিকানা নেওয়া প্রতিটি সময় এটি মূল্যায়ন করার সময় একটি নতুন ঘটনা বরাদ্দ করে, তাই আমরা এই শেষ দুটি লাইন একত্রিত করতে পারি।

http://golang.org/doc/effective_go.html#functions

তবে এটি বেশ কয়েকটি প্রশ্ন উত্থাপন করে।

1 - উদাহরণস্বরূপ 1, স্ট্রাকটি গাদাতে ঘোষিত হয়। উদাহরণ 2 সম্পর্কে কি? এটি স্ট্যাকের উপর একইভাবে ঘোষিত হয়েছে এটি সি তে হবে কি না এটিও গাদা হয়ে যায়?

2 - যদি স্ট্যাকের উপর উদাহরণ 2 ঘোষণা করা হয় তবে ফাংশনটি ফিরে আসার পরে এটি কীভাবে উপলব্ধ থাকবে?

3 - উদাহরণস্বরূপ 2 যদি গাদাতে ঘোষিত হয়, তবে স্ট্রাক্টগুলি রেফারেন্সের পরিবর্তে মান দ্বারা কীভাবে পাস হবে? এই ক্ষেত্রে পয়েন্টার বিন্দু কি?

উত্তর:


170

এটি লক্ষণীয় যে "স্ট্যাক" এবং "হিপ" শব্দটি কোথাও ভাষার অনুচ্ছেদে উপস্থিত হয় না। আপনার প্রশ্নটি "... স্ট্যাকের উপরে ঘোষিত হয়েছে", এবং "... গাদাতে ঘোষিত হয়েছে" দিয়ে উচ্চারিত হয়েছে তবে নোট করুন যে গো ঘোষণার বাক্য গঠন স্ট্যাক বা গাদা সম্পর্কে কিছুই বলে না।

এটি প্রযুক্তিগতভাবে আপনার সমস্ত প্রশ্নের উত্তর বাস্তবায়ন নির্ভর করে। বাস্তবে বাস্তবে, সেখানে একটি স্ট্যাক (প্রতি গোরোটিন!) এবং একটি গাদা এবং কিছু জিনিস স্ট্যাকের উপর এবং কিছু স্তূপে যায়। কিছু ক্ষেত্রে সংকলক কঠোর নিয়মগুলি অনুসরণ করে (যেমন " newসর্বদা গাদাতে বরাদ্দ দেয়") এবং অন্যদের মধ্যে কম্পাইলার "অব্যাহতি বিশ্লেষণ" করে সিদ্ধান্ত নেয় যে কোনও বস্তু স্ট্যাকের উপরে বাঁচতে পারে বা এটি অবশ্যই গাদাতে বরাদ্দ করা উচিত decide

আপনার উদাহরণ 2 এ, এস্কেপ বিশ্লেষণ স্ট্রাকের পলায়নের দিকে নির্দেশকটি দেখায় এবং তাই সংকলককে কাঠামো বরাদ্দ করতে হবে। আমি মনে করি গো এর বাস্তবায়ন এই ক্ষেত্রে একটি কঠোর নিয়ম অনুসরণ করেছে তবে এটি হ'ল যদি ঠিকানাটি কোনও কাঠামোর কোনও অংশ নেওয়া হয় তবে স্ট্রাকটি গাদা হয়ে যায়।

প্রশ্ন 3 এর জন্য, আমরা পরিভাষা সম্পর্কে বিভ্রান্ত হওয়ার ঝুঁকি নিয়ে থাকি। গো এর সমস্ত কিছু মান দ্বারা পাস হয়, রেফারেন্স দ্বারা কোনও পাস হয় না। এখানে আপনি একটি পয়েন্টার মানটি ফিরিয়ে দিচ্ছেন। পয়েন্টার পয়েন্ট কি? আপনার উদাহরণের নিম্নলিখিত পরিবর্তন বিবেচনা করুন:

type MyStructType struct{}

func myFunction1() (*MyStructType, error) {
    var chunk *MyStructType = new(MyStructType)
    // ...
    return chunk, nil
}

func myFunction2() (MyStructType, error) {
    var chunk MyStructType
    // ...
    return chunk, nil
}

type bigStruct struct {
    lots [1e6]float64
}

func myFunction3() (bigStruct, error) {
    var chunk bigStruct
    // ...
    return chunk, nil
}

কাঠামোর ঠিকানার চেয়ে স্ট্রাক্ট ফিরিয়ে দিতে আমি আমার ফাংশন 2 সংশোধন করেছি। এখন MyFunction1 এবং myFunction2 এর সমাবেশের আউটপুট তুলনা করুন,

--- prog list "myFunction1" ---
0000 (s.go:5) TEXT    myFunction1+0(SB),$16-24
0001 (s.go:6) MOVQ    $type."".MyStructType+0(SB),(SP)
0002 (s.go:6) CALL    ,runtime.new+0(SB)
0003 (s.go:6) MOVQ    8(SP),AX
0004 (s.go:8) MOVQ    AX,.noname+0(FP)
0005 (s.go:8) MOVQ    $0,.noname+8(FP)
0006 (s.go:8) MOVQ    $0,.noname+16(FP)
0007 (s.go:8) RET     ,

--- prog list "myFunction2" ---
0008 (s.go:11) TEXT    myFunction2+0(SB),$0-16
0009 (s.go:12) LEAQ    chunk+0(SP),DI
0010 (s.go:12) MOVQ    $0,AX
0011 (s.go:14) LEAQ    .noname+0(FP),BX
0012 (s.go:14) LEAQ    chunk+0(SP),BX
0013 (s.go:14) MOVQ    $0,.noname+0(FP)
0014 (s.go:14) MOVQ    $0,.noname+8(FP)
0015 (s.go:14) RET     ,

চিন্তা করবেন না যে এখানে MyFunction1 আউটপুট পিটারসো (দুর্দান্ত) উত্তরের চেয়ে আলাদা। আমরা স্পষ্টতই বিভিন্ন সংকলক চালাচ্ছি। অন্যথায়, দেখুন যে আমি আমার মাইক্রাচটপ টাইপ * মাইস্ট্রাক্ট টাইপ না করে আমার স্ট্রাস্টটাইপটি ফিরিয়ে আনতে চাইছি F রানটাইম.নিউতে কল চলে গেছে, যা কিছু ক্ষেত্রে ভাল জিনিস হবে। যদিও ধরে থাকুন, এখানে আমার ফাংশন 3,

--- prog list "myFunction3" ---
0016 (s.go:21) TEXT    myFunction3+0(SB),$8000000-8000016
0017 (s.go:22) LEAQ    chunk+-8000000(SP),DI
0018 (s.go:22) MOVQ    $0,AX
0019 (s.go:22) MOVQ    $1000000,CX
0020 (s.go:22) REP     ,
0021 (s.go:22) STOSQ   ,
0022 (s.go:24) LEAQ    chunk+-8000000(SP),SI
0023 (s.go:24) LEAQ    .noname+0(FP),DI
0024 (s.go:24) MOVQ    $1000000,CX
0025 (s.go:24) REP     ,
0026 (s.go:24) MOVSQ   ,
0027 (s.go:24) MOVQ    $0,.noname+8000000(FP)
0028 (s.go:24) MOVQ    $0,.noname+8000008(FP)
0029 (s.go:24) RET     ,

রানটাইম.নিউয়ের কাছে এখনও কোনও কল নেই, এবং হ্যাঁ এটি 8MB অবজেক্টকে মান দ্বারা ফিরিয়ে আনতে কাজ করে। এটি কাজ করে, তবে আপনি সাধারণত চান না। এখানে একটি পয়েন্টারের বিন্দুটি 8MB অবজেক্টের দিকে ঠেলাঠেলি করা এড়ানো হবে।


9
দুর্দান্ত ধন্যবাদ। আমি সত্যিই জিজ্ঞাসা করছিলাম না "বিন্দুগুলির বিন্দুটি কী আদৌ", এটি আরও অনেকটা "পয়েন্টারগুলির বিন্দুটি কী তখন মানগুলি যখন পয়েন্টারগুলির মতো আচরণ করে" বলে মনে হয়, এবং সেই ক্ষেত্রে যাইহোক আপনার উত্তরের দ্বারা মোড রেন্ডার করা হয়।
জো

25
সমাবেশের একটি সংক্ষিপ্ত ব্যাখ্যা প্রশংসা হবে।
এলিফ্যান্ট

59
type MyStructType struct{}

func myFunction1() (*MyStructType, error) {
    var chunk *MyStructType = new(MyStructType)
    // ...
    return chunk, nil
}

func myFunction2() (*MyStructType, error) {
    var chunk MyStructType
    // ...
    return &chunk, nil
}

উভয় ক্ষেত্রেই, গো এর বর্তমান বাস্তবায়নগুলি গাদা জাতীয় structধরণের জন্য মেমরি বরাদ্দ MyStructTypeকরে এবং তার ঠিকানা ফেরত দেয়। ফাংশন সমতুল্য; সংকলক asm উত্স একই।

--- prog list "myFunction1" ---
0000 (temp.go:9) TEXT    myFunction1+0(SB),$8-12
0001 (temp.go:10) MOVL    $type."".MyStructType+0(SB),(SP)
0002 (temp.go:10) CALL    ,runtime.new+0(SB)
0003 (temp.go:10) MOVL    4(SP),BX
0004 (temp.go:12) MOVL    BX,.noname+0(FP)
0005 (temp.go:12) MOVL    $0,AX
0006 (temp.go:12) LEAL    .noname+4(FP),DI
0007 (temp.go:12) STOSL   ,
0008 (temp.go:12) STOSL   ,
0009 (temp.go:12) RET     ,

--- prog list "myFunction2" ---
0010 (temp.go:15) TEXT    myFunction2+0(SB),$8-12
0011 (temp.go:16) MOVL    $type."".MyStructType+0(SB),(SP)
0012 (temp.go:16) CALL    ,runtime.new+0(SB)
0013 (temp.go:16) MOVL    4(SP),BX
0014 (temp.go:18) MOVL    BX,.noname+0(FP)
0015 (temp.go:18) MOVL    $0,AX
0016 (temp.go:18) LEAL    .noname+4(FP),DI
0017 (temp.go:18) STOSL   ,
0018 (temp.go:18) STOSL   ,
0019 (temp.go:18) RET     ,

কল

একটি ফাংশন কলে, ফাংশন মান এবং আর্গুমেন্টগুলি স্বাভাবিক ক্রমে মূল্যায়ন করা হয়। তাদের মূল্যায়ন করার পরে, কলটির পরামিতিগুলি ফাংশনে মান দ্বারা প্রেরণ করা হয় এবং ডাকা ফাংশনটি কার্যকর করা শুরু করে। ফাংশনটি ফিরে আসার সাথে সাথে ফাংশনের রিটার্ন পরামিতিগুলি কলিং ফাংশনে ফিরে যেতে হবে।

সমস্ত ফাংশন এবং রিটার্ন পরামিতি মান দ্বারা পাস করা হয়। প্রকারের সাথে রিটার্ন প্যারামিটার মান *MyStructTypeএকটি ঠিকানা।


অনেক ধন্যবাদ! উত্সাহিত, তবে পালানোর বিশ্লেষণ সম্পর্কে কিছুটা বলে আমি সোনিয়া গ্রহণ করছি।
জো

1
পিটারসো, আপনি এবং @ সোনিয়া কীভাবে এই সমাবেশটি তৈরি করছেন? আপনার দুজনেরই একই বিন্যাস রয়েছে। কমান্ড / ফ্ল্যাগ নির্বিশেষে আমি এটি উত্পাদন করতে পারি না, অজডাম্প চেষ্টা করেছিলাম, যান সরঞ্জাম, ওটুল।
10 ক্লাস

3
আহ, বুঝেছি - gcflags।
10 ক্লাস

30

গো এর এফএকিউ অনুসারে :

যদি সংকলকটি প্রমাণ করতে না পারে যে ফাংশনটি ফিরে আসার পরে চলকটি রেফারেন্স করা হয় না, তবে সংকলককে পয়েন্টারের ত্রুটিগুলি এড়ানোর জন্য আবর্জনা-সংগৃহীত হিপে চলকটি বরাদ্দ করতে হবে।


11

আপনার ভেরিয়েবলটি স্ট্যাক বা হিপগুলিতে বরাদ্দ করা হয়েছে তা আপনি সর্বদা জানেন না।
...
আপনার ভেরিয়েবলগুলি কোথায় বরাদ্দ করা হয়েছে তা যদি জানতে প্রয়োজন তবে "যান বিল্ড" বা "যান চালান" (যেমন, go run -gcflags -m app.go) তে "-m" গিসি পতাকাটি পাস করুন ।

সূত্র: http://devs.cloudimmune.com/gotchas-and-common-mistakes-in-go-golang/index.html#stack_heap_vars


0
func Function1() (*MyStructType, error) {
    var chunk *MyStructType = new(HeaderChunk)

    ...

    return chunk, nil
}


func Function2() (*MyStructType, error) {
    var chunk MyStructType

    ...

    return &chunk, nil
}

ফাংশন 1 এবং ফাংশন 2 ইনলাইন ফাংশন হতে পারে। এবং রিটার্ন ভেরিয়েবল পালাতে পারবে না। গাদাতে ভেরিয়েবল বরাদ্দ করার প্রয়োজন নেই।

আমার উদাহরণ কোড:

 1  package main
 2  
 3  type S struct {
 4          x int
 5  }
 6  
 7  func main() {
 8          F1()
 9          F2()
10          F3()
11  }
12  
13  func F1() *S {
14          s := new(S)
15          return s
16  }
17  
18  func F2() *S {
19          s := S{x: 10}
20          return &s
21  }
22  
23  func F3() S {
24          s := S{x: 9}
25          return s
26  }

সেমিডির আউটপুট অনুযায়ী:

go run -gcflags -m test.go

আউটপুট:

# command-line-arguments
./test.go:13:6: can inline F1
./test.go:18:6: can inline F2
./test.go:23:6: can inline F3
./test.go:7:6: can inline main
./test.go:8:4: inlining call to F1
./test.go:9:4: inlining call to F2
./test.go:10:4: inlining call to F3
/var/folders/nr/lxtqsz6x1x1gfbyp1p0jy4p00000gn/T/go-build333003258/b001/_gomod_.go:6:6: can inline init.0
./test.go:8:4: main new(S) does not escape
./test.go:9:4: main &s does not escape
./test.go:14:10: new(S) escapes to heap
./test.go:20:9: &s escapes to heap
./test.go:19:2: moved to heap: s

সংকলকটি যথেষ্ট স্মার্ট হলে এফ 1 () এফ 2 () এফ 3 () কল করা যাবে না। কারণ এটি কোনও উপায় করে না।

ভেরিয়েবলটি গাদা বা স্ট্যাকের জন্য বরাদ্দ করা হয়েছে কিনা সে বিষয়ে চিন্তা করবেন না, কেবল এটি ব্যবহার করুন। এটি প্রয়োজনে মিটেক্স বা চ্যানেল দ্বারা সুরক্ষিত করুন।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.