برنامه نویسی

بروید #006 – شرط و حلقه ها: جریان کنترل بدون درهم و برهمی

شرط ها و حلقه های Go با طراحی مینیمالیستی هستند ، اما سادگی آنها تصمیمات دقیق حافظه را پنهان می کند. بیایید کشف کنیم چگونه ifبا switchوت for تعامل با بخش های پشته ، پشته و داده ها – و در جایی که تخصیص های پنهان در آن خزش می شوند.


رمز

package main  

func main() {  
    // Conditional with stack-allocated variable  
    if score := 42; score > 50 {  
        // ...  
    }  

    // Loop with slice iteration  
    nums := []int{10, 20, 30}  // Slice header (stack), backing array (heap)  
    for i, n := range nums {  
        // ...  
    }  

    // Loop closure capturing variable  
    for _, n := range nums {  
        func() {  
            println(n)  // n escapes to heap  
        }()  
    }  
}  
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید


تقسیم بندی حافظه تجسم شد

+-------------------+   Lowest Address  
|      Code         |  
|-------------------|  
| main()            |  // Compiled logic for conditionals/loops  
| range handling    |  // Machine code for slice iteration  
+-------------------+  
|      Data         |  
|-------------------|  
| (No constants)    |  
+-------------------+  
|      Stack        |  
|-------------------|  
| score (int = 42)  |  // if-scoped variable  
| nums (slice)      |  // Pointer to heap array  
| i, n (loop vars)  |  // Per-iteration copies  
+-------------------+  
|      Heap         |  
|-------------------|  
| []int backing     |  // nums' array [10, 20, 30]  
| n (int copies)    |  // Captured by closure (one per iteration)  
+-------------------+   Highest Address  
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید


تجزیه رفتار حافظه

1. شرط بندی (ifبا switch)

  • متغیرهای اعلام شده در if/switch:

    • score در if score := 42; ... است ، پشتهبشر
    • به بلوک ، بلافاصله تمیز شد.
  • بدون تخصیص پشته ضمنی مگر اینکه متغیرها فرار کنند (به عنوان مثال ، به بسته شدن).

2. حلقه ها (forبا range)

  • متغیرهای حلقه:

    • i وت n در for i, n := range nums هستند استفاده مجدد در هر تکرار (اختصاص داده شده).
    • مقادیر کپی می شوند ، بنابراین اصلاح n بر قطعه اصلی تأثیر نمی گذارد.
  • آرایه پشتی برش:

    • nums := []int{10, 20, 30} هدر برش (اشاره گر ، لن ، کلاه) را روی پشتهبشر
    • آرایه واقعی [10, 20, 30] زندگی در پشتهبشر

3. بسته شدن در حلقه ها

  • متغیرهای ضبط شده:

    • n در بسته شدن func() { println(n) }() فرار به پشتهبشر
    • هر تکرار n برای افزایش تکرار حلقه در پشته کپی شده است.
  • با تجزیه و تحلیل فرار تأیید کنید:

  go build -gcflags="-m" main.go  
  # ./main.go:12:3: ... n escapes to heap  
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید


چرا این مهم است

  • استفاده مجدد از متغیر حلقه: بروید همان آدرس حافظه را برای استفاده کنید i وت n در هر تکرار

    • گودا: goroutines در حلقه ها متغیرهای حلقه را ضبط می کنند (به عنوان مثال ، go func() { ... }()) اسیر آخرین ارزش از i/nبشر رفع:
    for _, n := range nums {  
        n := n  // Create a stack copy per iteration  
        go func() { println(n) }()  
    }  
    
  • بازده برش: برش های بزرگ تخصیص پشته را برای پشتوانه آرایه ها مجبور می کنند. قبل از اندازه با make برای جلوگیری از محاصره.


نکات بهینه سازی

  1. از بسته شدن در حلقه های داغ خودداری کنید: برای نگه داشتن متغیرها در پشته ، از پارامترهای صریح استفاده کنید.
  2. برش های قبل از تخصیص:
   data := make([]int, 0, 1000)  // Heap-allocated but avoids reallocations  
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

  1. در شرایط از رابط {} مراقب باشید:
   var val interface{} = 42  // Heap escape  
   if val == 42 { ... }      // Type check overhead  
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید


بینش کلیدی: برو for حلقه ها برای به حداقل رساندن تخصیص از متغیرها استفاده مجدد می کنند – یک انتخاب طراحی که سریع است اما با تعطیلی و گوروها احتیاط می کند.

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا