[{"data":1,"prerenderedAt":2899},["ShallowReactive",2],{"page-\u002Fgo\u002F27-profiling-and-performance":3},{"id":4,"title":5,"body":6,"description":2892,"extension":2893,"meta":2894,"navigation":180,"path":2895,"seo":2896,"stem":2897,"__hash__":2898},"content\u002Fgo\u002F27-profiling-and-performance.md","27 — Profiling & Performance",{"type":7,"value":8,"toc":2886},"minimark",[9,13,18,2779,2870,2874,2882],[10,11,5],"h1",{"id":12},"_27-profiling-performance",[14,15,17],"h2",{"id":16},"the-optimization-workflow","The Optimization Workflow",[19,20,22,32,39],"code-wrapper",{"language":21},"text",[23,24,29],"pre",{"className":25,"code":27,"language":21,"meta":28},[26],"language-text","1. MEASURE — never optimize without profiling. \"Premature optimization is the root of all evil.\"\n2. PROFILE — find the bottleneck (CPU, memory, goroutine, lock contention).\n3. OPTIMIZE — the top consumer first. A function at 1% of CPU isn't worth optimizing.\n4. BENCHMARK — measure before and after with benchstat. If no improvement, revert.\n5. REPEAT — the next bottleneck is now visible.\n\nKey principle: ALLOCATIONS are the #1 performance problem in Go.\n  - Heap allocations trigger GC (stop-the-world pauses, concurrent scan).\n  - Stack allocations are free (no GC, no allocation overhead).\n  - Reducing allocs\u002Fop often improves performance more than micro-optimizing CPU.\n","",[30,31,27],"code",{"__ignoreMap":28},[14,33,35,38],{"id":34},"pprof-cpu-and-heap-profiling",[30,36,37],{},"pprof"," — CPU and Heap Profiling",[19,40,42,257,264],{"language":41},"bash",[23,43,46],{"className":44,"code":45,"language":41,"meta":28,"style":28},"language-bash shiki shiki-themes github-light github-dark","# ─── CPU profile from a benchmark ───\ngo test -bench=BenchmarkX -cpuprofile=cpu.out\ngo tool pprof cpu.out\n(pprof) top              # top functions by cumulative time\n(pprof) top10 -cum       # top 10 by cumulative (inclusive of callees)\n(pprof) list FuncName    # annotated source — time per line\n(pprof) web              # graphviz call graph\n(pprof) weblist FuncName # annotated source in browser\n\n# ─── Heap profile ───\ngo test -bench=BenchmarkX -memprofile=mem.out\ngo tool pprof mem.out\n(pprof) top              # top allocating functions\n\n# ─── Web UI (Go 1.24+: integrated pprof UI) ───\ngo tool pprof -http=:8080 cpu.out\n# Opens a browser with flame graphs, source view, and call graph.\n",[30,47,48,57,75,89,107,125,143,158,175,182,188,200,212,226,231,237,251],{"__ignoreMap":28},[49,50,53],"span",{"class":51,"line":52},"line",1,[49,54,56],{"class":55},"sdCPZ","# ─── CPU profile from a benchmark ───\n",[49,58,60,64,68,72],{"class":51,"line":59},2,[49,61,63],{"class":62},"sIsaT","go",[49,65,67],{"class":66},"sJ6F3"," test",[49,69,71],{"class":70},"snvgF"," -bench=BenchmarkX",[49,73,74],{"class":70}," -cpuprofile=cpu.out\n",[49,76,78,80,83,86],{"class":51,"line":77},3,[49,79,63],{"class":62},[49,81,82],{"class":66}," tool",[49,84,85],{"class":66}," pprof",[49,87,88],{"class":66}," cpu.out\n",[49,90,92,96,98,101,104],{"class":51,"line":91},4,[49,93,95],{"class":94},"ssxIu","(",[49,97,37],{"class":62},[49,99,100],{"class":94},") ",[49,102,103],{"class":62},"top",[49,105,106],{"class":55},"              # top functions by cumulative time\n",[49,108,110,112,114,116,119,122],{"class":51,"line":109},5,[49,111,95],{"class":94},[49,113,37],{"class":62},[49,115,100],{"class":94},[49,117,118],{"class":62},"top10",[49,120,121],{"class":70}," -cum",[49,123,124],{"class":55},"       # top 10 by cumulative (inclusive of callees)\n",[49,126,128,130,132,134,137,140],{"class":51,"line":127},6,[49,129,95],{"class":94},[49,131,37],{"class":62},[49,133,100],{"class":94},[49,135,136],{"class":62},"list",[49,138,139],{"class":66}," FuncName",[49,141,142],{"class":55},"    # annotated source — time per line\n",[49,144,146,148,150,152,155],{"class":51,"line":145},7,[49,147,95],{"class":94},[49,149,37],{"class":62},[49,151,100],{"class":94},[49,153,154],{"class":62},"web",[49,156,157],{"class":55},"              # graphviz call graph\n",[49,159,161,163,165,167,170,172],{"class":51,"line":160},8,[49,162,95],{"class":94},[49,164,37],{"class":62},[49,166,100],{"class":94},[49,168,169],{"class":62},"weblist",[49,171,139],{"class":66},[49,173,174],{"class":55}," # annotated source in browser\n",[49,176,178],{"class":51,"line":177},9,[49,179,181],{"emptyLinePlaceholder":180},true,"\n",[49,183,185],{"class":51,"line":184},10,[49,186,187],{"class":55},"# ─── Heap profile ───\n",[49,189,191,193,195,197],{"class":51,"line":190},11,[49,192,63],{"class":62},[49,194,67],{"class":66},[49,196,71],{"class":70},[49,198,199],{"class":70}," -memprofile=mem.out\n",[49,201,203,205,207,209],{"class":51,"line":202},12,[49,204,63],{"class":62},[49,206,82],{"class":66},[49,208,85],{"class":66},[49,210,211],{"class":66}," mem.out\n",[49,213,215,217,219,221,223],{"class":51,"line":214},13,[49,216,95],{"class":94},[49,218,37],{"class":62},[49,220,100],{"class":94},[49,222,103],{"class":62},[49,224,225],{"class":55},"              # top allocating functions\n",[49,227,229],{"class":51,"line":228},14,[49,230,181],{"emptyLinePlaceholder":180},[49,232,234],{"class":51,"line":233},15,[49,235,236],{"class":55},"# ─── Web UI (Go 1.24+: integrated pprof UI) ───\n",[49,238,240,242,244,246,249],{"class":51,"line":239},16,[49,241,63],{"class":62},[49,243,82],{"class":66},[49,245,85],{"class":66},[49,247,248],{"class":70}," -http=:8080",[49,250,88],{"class":66},[49,252,254],{"class":51,"line":253},17,[49,255,256],{"class":55},"# Opens a browser with flame graphs, source view, and call graph.\n",[258,259,261,263],"h3",{"id":260},"pprof-in-a-running-server",[30,262,37],{}," in a Running Server",[19,265,266,367,371],{"language":63},[23,267,270],{"className":268,"code":269,"language":63,"meta":28,"style":28},"language-go shiki shiki-themes github-light github-dark","\u002F\u002F import _ \"net\u002Fhttp\u002Fpprof\"  \u002F\u002F registers \u002Fdebug\u002Fpprof\u002F on the default mux\n\n\u002F\u002F Serve pprof on a separate port (don't expose to the public):\ngo func() {\n    log.Println(http.ListenAndServe(\"localhost:6060\", nil))\n}()\n\n\u002F\u002F Then profile the live server:\n\u002F\u002F go tool pprof http:\u002F\u002Flocalhost:6060\u002Fdebug\u002Fpprof\u002Fprofile?seconds=30  # 30s CPU\n\u002F\u002F go tool pprof http:\u002F\u002Flocalhost:6060\u002Fdebug\u002Fpprof\u002Fheap                 # heap allocations\n\u002F\u002F go tool pprof http:\u002F\u002Flocalhost:6060\u002Fdebug\u002Fpprof\u002Fgoroutine           # goroutine stacks\n\u002F\u002F go tool pprof http:\u002F\u002Flocalhost:6060\u002Fdebug\u002Fpprof\u002Fblock                # blocking (needs runtime.SetBlockProfileRate)\n\u002F\u002F go tool pprof http:\u002F\u002Flocalhost:6060\u002Fdebug\u002Fpprof\u002Fmutex                # mutex contention\n",[30,271,272,280,284,289,300,328,333,337,342,347,352,357,362],{"__ignoreMap":28},[49,273,274,277],{"class":51,"line":52},[49,275,276],{"class":55},"\u002F\u002F import _ \"net\u002Fhttp\u002Fpprof\"",[49,278,279],{"class":55},"  \u002F\u002F registers \u002Fdebug\u002Fpprof\u002F on the default mux\n",[49,281,282],{"class":51,"line":59},[49,283,181],{"emptyLinePlaceholder":180},[49,285,286],{"class":51,"line":77},[49,287,288],{"class":55},"\u002F\u002F Serve pprof on a separate port (don't expose to the public):\n",[49,290,291,294,297],{"class":51,"line":91},[49,292,63],{"class":293},"svdQ7",[49,295,296],{"class":293}," func",[49,298,299],{"class":94},"() {\n",[49,301,302,305,308,311,314,316,319,322,325],{"class":51,"line":109},[49,303,304],{"class":94},"    log.",[49,306,307],{"class":62},"Println",[49,309,310],{"class":94},"(http.",[49,312,313],{"class":62},"ListenAndServe",[49,315,95],{"class":94},[49,317,318],{"class":66},"\"localhost:6060\"",[49,320,321],{"class":94},", ",[49,323,324],{"class":70},"nil",[49,326,327],{"class":94},"))\n",[49,329,330],{"class":51,"line":127},[49,331,332],{"class":94},"}()\n",[49,334,335],{"class":51,"line":145},[49,336,181],{"emptyLinePlaceholder":180},[49,338,339],{"class":51,"line":160},[49,340,341],{"class":55},"\u002F\u002F Then profile the live server:\n",[49,343,344],{"class":51,"line":177},[49,345,346],{"class":55},"\u002F\u002F go tool pprof http:\u002F\u002Flocalhost:6060\u002Fdebug\u002Fpprof\u002Fprofile?seconds=30  # 30s CPU\n",[49,348,349],{"class":51,"line":184},[49,350,351],{"class":55},"\u002F\u002F go tool pprof http:\u002F\u002Flocalhost:6060\u002Fdebug\u002Fpprof\u002Fheap                 # heap allocations\n",[49,353,354],{"class":51,"line":190},[49,355,356],{"class":55},"\u002F\u002F go tool pprof http:\u002F\u002Flocalhost:6060\u002Fdebug\u002Fpprof\u002Fgoroutine           # goroutine stacks\n",[49,358,359],{"class":51,"line":202},[49,360,361],{"class":55},"\u002F\u002F go tool pprof http:\u002F\u002Flocalhost:6060\u002Fdebug\u002Fpprof\u002Fblock                # blocking (needs runtime.SetBlockProfileRate)\n",[49,363,364],{"class":51,"line":214},[49,365,366],{"class":55},"\u002F\u002F go tool pprof http:\u002F\u002Flocalhost:6060\u002Fdebug\u002Fpprof\u002Fmutex                # mutex contention\n",[14,368,370],{"id":369},"escape-analysis-the-allocation-decision","Escape Analysis — The Allocation Decision",[19,372,373,714,718,729],{"language":63},[23,374,376],{"className":268,"code":375,"language":63,"meta":28,"style":28},"\u002F\u002F The compiler decides stack vs heap via escape analysis.\n\u002F\u002F See the decisions:\n\u002F\u002F   go build -gcflags='-m' .\u002F...        # summary\n\u002F\u002F   go build -gcflags='-m -m' .\u002F...     # verbose (explains WHY)\n\n\u002F\u002F ─── Stack-allocated (no escape) ───\nfunc noEscape() int {\n    x := 42       \u002F\u002F does not escape — stays on stack, free\n    return x\n}\n\n\u002F\u002F ─── Heap-allocated (escapes — address returned) ───\nfunc escapes() *int {\n    x := 42       \u002F\u002F escapes to heap — &x leaves the function\n    return &x      \u002F\u002F GC manages x's lifetime\n}\n\n\u002F\u002F ─── Interface boxing causes escape ───\nfunc interfaceEscape() {\n    x := 42\n    var i any = x  \u002F\u002F x escapes — interface stores (type, *x)\n    fmt.Println(i)\n}\n\n\u002F\u002F ─── The fmt.Println escape (common in hot paths) ───\nfunc fmtEscape() {\n    for i := 0; i \u003C 1000000; i++ {\n        fmt.Println(i)  \u002F\u002F ⚠️ i escapes to heap — fmt takes ...any\n    }\n}\n\u002F\u002F Fix: use strconv (no interface):\nfunc noFmtEscape() {\n    for i := 0; i \u003C 1000000; i++ {\n        _ = strconv.Itoa(i)  \u002F\u002F i stays on stack\n    }\n}\n",[30,377,378,383,388,393,398,402,407,424,438,446,451,455,460,474,485,498,502,506,512,522,532,553,564,569,574,580,590,620,634,640,645,651,661,684,704,709],{"__ignoreMap":28},[49,379,380],{"class":51,"line":52},[49,381,382],{"class":55},"\u002F\u002F The compiler decides stack vs heap via escape analysis.\n",[49,384,385],{"class":51,"line":59},[49,386,387],{"class":55},"\u002F\u002F See the decisions:\n",[49,389,390],{"class":51,"line":77},[49,391,392],{"class":55},"\u002F\u002F   go build -gcflags='-m' .\u002F...        # summary\n",[49,394,395],{"class":51,"line":91},[49,396,397],{"class":55},"\u002F\u002F   go build -gcflags='-m -m' .\u002F...     # verbose (explains WHY)\n",[49,399,400],{"class":51,"line":109},[49,401,181],{"emptyLinePlaceholder":180},[49,403,404],{"class":51,"line":127},[49,405,406],{"class":55},"\u002F\u002F ─── Stack-allocated (no escape) ───\n",[49,408,409,412,415,418,421],{"class":51,"line":145},[49,410,411],{"class":293},"func",[49,413,414],{"class":62}," noEscape",[49,416,417],{"class":94},"() ",[49,419,420],{"class":293},"int",[49,422,423],{"class":94}," {\n",[49,425,426,429,432,435],{"class":51,"line":160},[49,427,428],{"class":94},"    x ",[49,430,431],{"class":293},":=",[49,433,434],{"class":70}," 42",[49,436,437],{"class":55},"       \u002F\u002F does not escape — stays on stack, free\n",[49,439,440,443],{"class":51,"line":177},[49,441,442],{"class":293},"    return",[49,444,445],{"class":94}," x\n",[49,447,448],{"class":51,"line":184},[49,449,450],{"class":94},"}\n",[49,452,453],{"class":51,"line":190},[49,454,181],{"emptyLinePlaceholder":180},[49,456,457],{"class":51,"line":202},[49,458,459],{"class":55},"\u002F\u002F ─── Heap-allocated (escapes — address returned) ───\n",[49,461,462,464,467,469,472],{"class":51,"line":214},[49,463,411],{"class":293},[49,465,466],{"class":62}," escapes",[49,468,417],{"class":94},[49,470,471],{"class":293},"*int",[49,473,423],{"class":94},[49,475,476,478,480,482],{"class":51,"line":228},[49,477,428],{"class":94},[49,479,431],{"class":293},[49,481,434],{"class":70},[49,483,484],{"class":55},"       \u002F\u002F escapes to heap — &x leaves the function\n",[49,486,487,489,492,495],{"class":51,"line":233},[49,488,442],{"class":293},[49,490,491],{"class":293}," &",[49,493,494],{"class":94},"x      ",[49,496,497],{"class":55},"\u002F\u002F GC manages x's lifetime\n",[49,499,500],{"class":51,"line":239},[49,501,450],{"class":94},[49,503,504],{"class":51,"line":253},[49,505,181],{"emptyLinePlaceholder":180},[49,507,509],{"class":51,"line":508},18,[49,510,511],{"class":55},"\u002F\u002F ─── Interface boxing causes escape ───\n",[49,513,515,517,520],{"class":51,"line":514},19,[49,516,411],{"class":293},[49,518,519],{"class":62}," interfaceEscape",[49,521,299],{"class":94},[49,523,525,527,529],{"class":51,"line":524},20,[49,526,428],{"class":94},[49,528,431],{"class":293},[49,530,531],{"class":70}," 42\n",[49,533,535,538,541,544,547,550],{"class":51,"line":534},21,[49,536,537],{"class":293},"    var",[49,539,540],{"class":94}," i ",[49,542,543],{"class":62},"any",[49,545,546],{"class":293}," =",[49,548,549],{"class":94}," x  ",[49,551,552],{"class":55},"\u002F\u002F x escapes — interface stores (type, *x)\n",[49,554,556,559,561],{"class":51,"line":555},22,[49,557,558],{"class":94},"    fmt.",[49,560,307],{"class":62},[49,562,563],{"class":94},"(i)\n",[49,565,567],{"class":51,"line":566},23,[49,568,450],{"class":94},[49,570,572],{"class":51,"line":571},24,[49,573,181],{"emptyLinePlaceholder":180},[49,575,577],{"class":51,"line":576},25,[49,578,579],{"class":55},"\u002F\u002F ─── The fmt.Println escape (common in hot paths) ───\n",[49,581,583,585,588],{"class":51,"line":582},26,[49,584,411],{"class":293},[49,586,587],{"class":62}," fmtEscape",[49,589,299],{"class":94},[49,591,593,596,598,600,603,606,609,612,615,618],{"class":51,"line":592},27,[49,594,595],{"class":293},"    for",[49,597,540],{"class":94},[49,599,431],{"class":293},[49,601,602],{"class":70}," 0",[49,604,605],{"class":94},"; i ",[49,607,608],{"class":293},"\u003C",[49,610,611],{"class":70}," 1000000",[49,613,614],{"class":94},"; i",[49,616,617],{"class":293},"++",[49,619,423],{"class":94},[49,621,623,626,628,631],{"class":51,"line":622},28,[49,624,625],{"class":94},"        fmt.",[49,627,307],{"class":62},[49,629,630],{"class":94},"(i)  ",[49,632,633],{"class":55},"\u002F\u002F ⚠️ i escapes to heap — fmt takes ...any\n",[49,635,637],{"class":51,"line":636},29,[49,638,639],{"class":94},"    }\n",[49,641,643],{"class":51,"line":642},30,[49,644,450],{"class":94},[49,646,648],{"class":51,"line":647},31,[49,649,650],{"class":55},"\u002F\u002F Fix: use strconv (no interface):\n",[49,652,654,656,659],{"class":51,"line":653},32,[49,655,411],{"class":293},[49,657,658],{"class":62}," noFmtEscape",[49,660,299],{"class":94},[49,662,664,666,668,670,672,674,676,678,680,682],{"class":51,"line":663},33,[49,665,595],{"class":293},[49,667,540],{"class":94},[49,669,431],{"class":293},[49,671,602],{"class":70},[49,673,605],{"class":94},[49,675,608],{"class":293},[49,677,611],{"class":70},[49,679,614],{"class":94},[49,681,617],{"class":293},[49,683,423],{"class":94},[49,685,687,690,693,696,699,701],{"class":51,"line":686},34,[49,688,689],{"class":94},"        _ ",[49,691,692],{"class":293},"=",[49,694,695],{"class":94}," strconv.",[49,697,698],{"class":62},"Itoa",[49,700,630],{"class":94},[49,702,703],{"class":55},"\u002F\u002F i stays on stack\n",[49,705,707],{"class":51,"line":706},35,[49,708,639],{"class":94},[49,710,712],{"class":51,"line":711},36,[49,713,450],{"class":94},[14,715,717],{"id":716},"allocation-reduction-the-top-patterns","Allocation Reduction — The Top Patterns",[258,719,721,722,725,726],{"id":720},"_1-stringsbuilder-instead-of","1. ",[30,723,724],{},"strings.Builder"," instead of ",[30,727,728],{},"+",[19,730,731,932,936],{"language":63},[23,732,734],{"className":268,"code":733,"language":63,"meta":28,"style":28},"\u002F\u002F ❌ O(n²) — each + allocates a new string:\nfunc badConcat(words []string) string {\n    s := \"\"\n    for _, w := range words {\n        s += w  \u002F\u002F allocates new string each iteration\n    }\n    return s\n}\n\n\u002F\u002F ✅ O(n) — amortized:\nfunc goodConcat(words []string) string {\n    var b strings.Builder\n    b.Grow(64)  \u002F\u002F pre-grow (estimate total size to avoid reallocation)\n    for _, w := range words {\n        b.WriteString(w)\n    }\n    return b.String()  \u002F\u002F single allocation for the final string\n}\n",[30,735,736,741,766,776,791,805,809,816,820,824,829,850,866,885,897,908,912,928],{"__ignoreMap":28},[49,737,738],{"class":51,"line":52},[49,739,740],{"class":55},"\u002F\u002F ❌ O(n²) — each + allocates a new string:\n",[49,742,743,745,748,750,754,757,760,762,764],{"class":51,"line":59},[49,744,411],{"class":293},[49,746,747],{"class":62}," badConcat",[49,749,95],{"class":94},[49,751,753],{"class":752},"sCrzJ","words",[49,755,756],{"class":94}," []",[49,758,759],{"class":293},"string",[49,761,100],{"class":94},[49,763,759],{"class":293},[49,765,423],{"class":94},[49,767,768,771,773],{"class":51,"line":77},[49,769,770],{"class":94},"    s ",[49,772,431],{"class":293},[49,774,775],{"class":66}," \"\"\n",[49,777,778,780,783,785,788],{"class":51,"line":91},[49,779,595],{"class":293},[49,781,782],{"class":94}," _, w ",[49,784,431],{"class":293},[49,786,787],{"class":293}," range",[49,789,790],{"class":94}," words {\n",[49,792,793,796,799,802],{"class":51,"line":109},[49,794,795],{"class":94},"        s ",[49,797,798],{"class":293},"+=",[49,800,801],{"class":94}," w  ",[49,803,804],{"class":55},"\u002F\u002F allocates new string each iteration\n",[49,806,807],{"class":51,"line":127},[49,808,639],{"class":94},[49,810,811,813],{"class":51,"line":145},[49,812,442],{"class":293},[49,814,815],{"class":94}," s\n",[49,817,818],{"class":51,"line":160},[49,819,450],{"class":94},[49,821,822],{"class":51,"line":177},[49,823,181],{"emptyLinePlaceholder":180},[49,825,826],{"class":51,"line":184},[49,827,828],{"class":55},"\u002F\u002F ✅ O(n) — amortized:\n",[49,830,831,833,836,838,840,842,844,846,848],{"class":51,"line":190},[49,832,411],{"class":293},[49,834,835],{"class":62}," goodConcat",[49,837,95],{"class":94},[49,839,753],{"class":752},[49,841,756],{"class":94},[49,843,759],{"class":293},[49,845,100],{"class":94},[49,847,759],{"class":293},[49,849,423],{"class":94},[49,851,852,854,857,860,863],{"class":51,"line":202},[49,853,537],{"class":293},[49,855,856],{"class":94}," b ",[49,858,859],{"class":62},"strings",[49,861,862],{"class":94},".",[49,864,865],{"class":62},"Builder\n",[49,867,868,871,874,876,879,882],{"class":51,"line":214},[49,869,870],{"class":94},"    b.",[49,872,873],{"class":62},"Grow",[49,875,95],{"class":94},[49,877,878],{"class":70},"64",[49,880,881],{"class":94},")  ",[49,883,884],{"class":55},"\u002F\u002F pre-grow (estimate total size to avoid reallocation)\n",[49,886,887,889,891,893,895],{"class":51,"line":228},[49,888,595],{"class":293},[49,890,782],{"class":94},[49,892,431],{"class":293},[49,894,787],{"class":293},[49,896,790],{"class":94},[49,898,899,902,905],{"class":51,"line":233},[49,900,901],{"class":94},"        b.",[49,903,904],{"class":62},"WriteString",[49,906,907],{"class":94},"(w)\n",[49,909,910],{"class":51,"line":239},[49,911,639],{"class":94},[49,913,914,916,919,922,925],{"class":51,"line":253},[49,915,442],{"class":293},[49,917,918],{"class":94}," b.",[49,920,921],{"class":62},"String",[49,923,924],{"class":94},"()  ",[49,926,927],{"class":55},"\u002F\u002F single allocation for the final string\n",[49,929,930],{"class":51,"line":508},[49,931,450],{"class":94},[258,933,935],{"id":934},"_2-pre-allocate-slices-and-maps","2. Pre-allocate slices and maps",[19,937,938,1176,1184],{"language":63},[23,939,941],{"className":268,"code":940,"language":63,"meta":28,"style":28},"\u002F\u002F ❌ Grows via reallocation (log(n) reallocs):\nfunc badCollect(items []int) []int {\n    var s []int  \u002F\u002F starts nil, grows via append\n    for _, item := range items {\n        s = append(s, transform(item))\n    }\n    return s\n}\n\n\u002F\u002F ✅ One allocation:\nfunc goodCollect(items []int) []int {\n    s := make([]int, 0, len(items))  \u002F\u002F pre-allocate capacity\n    for _, item := range items {\n        s = append(s, transform(item))  \u002F\u002F stays within cap — no realloc\n    }\n    return s\n}\n\n\u002F\u002F Same for maps:\nm := make(map[string]int, 1000)  \u002F\u002F pre-allocate buckets — avoids incremental rehashing\n",[30,942,943,948,971,983,997,1015,1019,1025,1029,1033,1038,1059,1089,1101,1119,1123,1129,1133,1137,1142],{"__ignoreMap":28},[49,944,945],{"class":51,"line":52},[49,946,947],{"class":55},"\u002F\u002F ❌ Grows via reallocation (log(n) reallocs):\n",[49,949,950,952,955,957,960,962,964,967,969],{"class":51,"line":59},[49,951,411],{"class":293},[49,953,954],{"class":62}," badCollect",[49,956,95],{"class":94},[49,958,959],{"class":752},"items",[49,961,756],{"class":94},[49,963,420],{"class":293},[49,965,966],{"class":94},") []",[49,968,420],{"class":293},[49,970,423],{"class":94},[49,972,973,975,978,980],{"class":51,"line":77},[49,974,537],{"class":293},[49,976,977],{"class":94}," s []",[49,979,420],{"class":293},[49,981,982],{"class":55},"  \u002F\u002F starts nil, grows via append\n",[49,984,985,987,990,992,994],{"class":51,"line":91},[49,986,595],{"class":293},[49,988,989],{"class":94}," _, item ",[49,991,431],{"class":293},[49,993,787],{"class":293},[49,995,996],{"class":94}," items {\n",[49,998,999,1001,1003,1006,1009,1012],{"class":51,"line":109},[49,1000,795],{"class":94},[49,1002,692],{"class":293},[49,1004,1005],{"class":62}," append",[49,1007,1008],{"class":94},"(s, ",[49,1010,1011],{"class":62},"transform",[49,1013,1014],{"class":94},"(item))\n",[49,1016,1017],{"class":51,"line":127},[49,1018,639],{"class":94},[49,1020,1021,1023],{"class":51,"line":145},[49,1022,442],{"class":293},[49,1024,815],{"class":94},[49,1026,1027],{"class":51,"line":160},[49,1028,450],{"class":94},[49,1030,1031],{"class":51,"line":177},[49,1032,181],{"emptyLinePlaceholder":180},[49,1034,1035],{"class":51,"line":184},[49,1036,1037],{"class":55},"\u002F\u002F ✅ One allocation:\n",[49,1039,1040,1042,1045,1047,1049,1051,1053,1055,1057],{"class":51,"line":190},[49,1041,411],{"class":293},[49,1043,1044],{"class":62}," goodCollect",[49,1046,95],{"class":94},[49,1048,959],{"class":752},[49,1050,756],{"class":94},[49,1052,420],{"class":293},[49,1054,966],{"class":94},[49,1056,420],{"class":293},[49,1058,423],{"class":94},[49,1060,1061,1063,1065,1068,1071,1073,1075,1078,1080,1083,1086],{"class":51,"line":202},[49,1062,770],{"class":94},[49,1064,431],{"class":293},[49,1066,1067],{"class":62}," make",[49,1069,1070],{"class":94},"([]",[49,1072,420],{"class":293},[49,1074,321],{"class":94},[49,1076,1077],{"class":70},"0",[49,1079,321],{"class":94},[49,1081,1082],{"class":62},"len",[49,1084,1085],{"class":94},"(items))  ",[49,1087,1088],{"class":55},"\u002F\u002F pre-allocate capacity\n",[49,1090,1091,1093,1095,1097,1099],{"class":51,"line":214},[49,1092,595],{"class":293},[49,1094,989],{"class":94},[49,1096,431],{"class":293},[49,1098,787],{"class":293},[49,1100,996],{"class":94},[49,1102,1103,1105,1107,1109,1111,1113,1116],{"class":51,"line":228},[49,1104,795],{"class":94},[49,1106,692],{"class":293},[49,1108,1005],{"class":62},[49,1110,1008],{"class":94},[49,1112,1011],{"class":62},[49,1114,1115],{"class":94},"(item))  ",[49,1117,1118],{"class":55},"\u002F\u002F stays within cap — no realloc\n",[49,1120,1121],{"class":51,"line":233},[49,1122,639],{"class":94},[49,1124,1125,1127],{"class":51,"line":239},[49,1126,442],{"class":293},[49,1128,815],{"class":94},[49,1130,1131],{"class":51,"line":253},[49,1132,450],{"class":94},[49,1134,1135],{"class":51,"line":508},[49,1136,181],{"emptyLinePlaceholder":180},[49,1138,1139],{"class":51,"line":514},[49,1140,1141],{"class":55},"\u002F\u002F Same for maps:\n",[49,1143,1144,1147,1149,1151,1153,1156,1159,1161,1164,1166,1168,1171,1173],{"class":51,"line":524},[49,1145,1146],{"class":94},"m ",[49,1148,431],{"class":293},[49,1150,1067],{"class":62},[49,1152,95],{"class":94},[49,1154,1155],{"class":293},"map",[49,1157,1158],{"class":94},"[",[49,1160,759],{"class":293},[49,1162,1163],{"class":94},"]",[49,1165,420],{"class":293},[49,1167,321],{"class":94},[49,1169,1170],{"class":70},"1000",[49,1172,881],{"class":94},[49,1174,1175],{"class":55},"\u002F\u002F pre-allocate buckets — avoids incremental rehashing\n",[258,1177,1179,1180,1183],{"id":1178},"_3-syncpool-for-reusable-objects","3. ",[30,1181,1182],{},"sync.Pool"," for reusable objects",[19,1185,1186,1375,1386],{"language":63},[23,1187,1189],{"className":268,"code":1188,"language":63,"meta":28,"style":28},"var bufPool = sync.Pool{\n    New: func() any { return new(bytes.Buffer) },\n}\n\nfunc process(data []byte) string {\n    buf := bufPool.Get().(*bytes.Buffer)\n    defer func() {\n        buf.Reset()       \u002F\u002F ⚠️ reset before returning to pool\n        bufPool.Put(buf)\n    }()\n    buf.Write(data)\n    return buf.String()\n}\n\u002F\u002F Reduces allocations in hot paths — buffers are reused instead of allocated.\n",[30,1190,1191,1212,1245,1249,1253,1276,1304,1313,1327,1338,1343,1354,1366,1370],{"__ignoreMap":28},[49,1192,1193,1196,1199,1201,1204,1206,1209],{"class":51,"line":52},[49,1194,1195],{"class":293},"var",[49,1197,1198],{"class":94}," bufPool ",[49,1200,692],{"class":293},[49,1202,1203],{"class":62}," sync",[49,1205,862],{"class":94},[49,1207,1208],{"class":62},"Pool",[49,1210,1211],{"class":94},"{\n",[49,1213,1214,1217,1219,1221,1223,1226,1229,1232,1234,1237,1239,1242],{"class":51,"line":59},[49,1215,1216],{"class":94},"    New: ",[49,1218,411],{"class":293},[49,1220,417],{"class":94},[49,1222,543],{"class":62},[49,1224,1225],{"class":94}," { ",[49,1227,1228],{"class":293},"return",[49,1230,1231],{"class":62}," new",[49,1233,95],{"class":94},[49,1235,1236],{"class":62},"bytes",[49,1238,862],{"class":94},[49,1240,1241],{"class":62},"Buffer",[49,1243,1244],{"class":94},") },\n",[49,1246,1247],{"class":51,"line":77},[49,1248,450],{"class":94},[49,1250,1251],{"class":51,"line":91},[49,1252,181],{"emptyLinePlaceholder":180},[49,1254,1255,1257,1260,1262,1265,1267,1270,1272,1274],{"class":51,"line":109},[49,1256,411],{"class":293},[49,1258,1259],{"class":62}," process",[49,1261,95],{"class":94},[49,1263,1264],{"class":752},"data",[49,1266,756],{"class":94},[49,1268,1269],{"class":293},"byte",[49,1271,100],{"class":94},[49,1273,759],{"class":293},[49,1275,423],{"class":94},[49,1277,1278,1281,1283,1286,1289,1292,1295,1297,1299,1301],{"class":51,"line":127},[49,1279,1280],{"class":94},"    buf ",[49,1282,431],{"class":293},[49,1284,1285],{"class":94}," bufPool.",[49,1287,1288],{"class":62},"Get",[49,1290,1291],{"class":94},"().(",[49,1293,1294],{"class":293},"*",[49,1296,1236],{"class":62},[49,1298,862],{"class":94},[49,1300,1241],{"class":62},[49,1302,1303],{"class":94},")\n",[49,1305,1306,1309,1311],{"class":51,"line":145},[49,1307,1308],{"class":293},"    defer",[49,1310,296],{"class":293},[49,1312,299],{"class":94},[49,1314,1315,1318,1321,1324],{"class":51,"line":160},[49,1316,1317],{"class":94},"        buf.",[49,1319,1320],{"class":62},"Reset",[49,1322,1323],{"class":94},"()       ",[49,1325,1326],{"class":55},"\u002F\u002F ⚠️ reset before returning to pool\n",[49,1328,1329,1332,1335],{"class":51,"line":177},[49,1330,1331],{"class":94},"        bufPool.",[49,1333,1334],{"class":62},"Put",[49,1336,1337],{"class":94},"(buf)\n",[49,1339,1340],{"class":51,"line":184},[49,1341,1342],{"class":94},"    }()\n",[49,1344,1345,1348,1351],{"class":51,"line":190},[49,1346,1347],{"class":94},"    buf.",[49,1349,1350],{"class":62},"Write",[49,1352,1353],{"class":94},"(data)\n",[49,1355,1356,1358,1361,1363],{"class":51,"line":202},[49,1357,442],{"class":293},[49,1359,1360],{"class":94}," buf.",[49,1362,921],{"class":62},[49,1364,1365],{"class":94},"()\n",[49,1367,1368],{"class":51,"line":214},[49,1369,450],{"class":94},[49,1371,1372],{"class":51,"line":228},[49,1373,1374],{"class":55},"\u002F\u002F Reduces allocations in hot paths — buffers are reused instead of allocated.\n",[258,1376,1378,1379,1382,1383,1385],{"id":1377},"_4-avoid-byte-string-conversions","4. Avoid ",[30,1380,1381],{},"[]byte"," ↔ ",[30,1384,759],{}," conversions",[19,1387,1388,1536,1540],{"language":63},[23,1389,1391],{"className":268,"code":1390,"language":63,"meta":28,"style":28},"\u002F\u002F ❌ Each conversion allocates a copy:\nfunc badContains(s string, sub string) bool {\n    return bytes.Contains([]byte(s), []byte(sub))  \u002F\u002F 2 allocations\n}\n\n\u002F\u002F ✅ Use the matching package (no conversion):\nfunc goodContains(s string, sub string) bool {\n    return strings.Contains(s, sub)  \u002F\u002F 0 allocations\n}\n\n\u002F\u002F ✅ For zero-copy (Go 1.20+, advanced — only for read-only):\n\u002F\u002F import \"unsafe\"\n\u002F\u002F b := unsafe.Slice(unsafe.StringData(s), len(s))  \u002F\u002F []byte sharing s's memory\n\u002F\u002F ⚠️ Never modify b — corrupts the read-only string table.\n",[30,1392,1393,1398,1427,1452,1456,1460,1465,1490,1505,1509,1513,1518,1523,1531],{"__ignoreMap":28},[49,1394,1395],{"class":51,"line":52},[49,1396,1397],{"class":55},"\u002F\u002F ❌ Each conversion allocates a copy:\n",[49,1399,1400,1402,1405,1407,1410,1413,1415,1418,1420,1422,1425],{"class":51,"line":59},[49,1401,411],{"class":293},[49,1403,1404],{"class":62}," badContains",[49,1406,95],{"class":94},[49,1408,1409],{"class":752},"s",[49,1411,1412],{"class":293}," string",[49,1414,321],{"class":94},[49,1416,1417],{"class":752},"sub",[49,1419,1412],{"class":293},[49,1421,100],{"class":94},[49,1423,1424],{"class":293},"bool",[49,1426,423],{"class":94},[49,1428,1429,1431,1434,1437,1439,1441,1444,1446,1449],{"class":51,"line":77},[49,1430,442],{"class":293},[49,1432,1433],{"class":94}," bytes.",[49,1435,1436],{"class":62},"Contains",[49,1438,1070],{"class":94},[49,1440,1269],{"class":293},[49,1442,1443],{"class":94},"(s), []",[49,1445,1269],{"class":293},[49,1447,1448],{"class":94},"(sub))  ",[49,1450,1451],{"class":55},"\u002F\u002F 2 allocations\n",[49,1453,1454],{"class":51,"line":91},[49,1455,450],{"class":94},[49,1457,1458],{"class":51,"line":109},[49,1459,181],{"emptyLinePlaceholder":180},[49,1461,1462],{"class":51,"line":127},[49,1463,1464],{"class":55},"\u002F\u002F ✅ Use the matching package (no conversion):\n",[49,1466,1467,1469,1472,1474,1476,1478,1480,1482,1484,1486,1488],{"class":51,"line":145},[49,1468,411],{"class":293},[49,1470,1471],{"class":62}," goodContains",[49,1473,95],{"class":94},[49,1475,1409],{"class":752},[49,1477,1412],{"class":293},[49,1479,321],{"class":94},[49,1481,1417],{"class":752},[49,1483,1412],{"class":293},[49,1485,100],{"class":94},[49,1487,1424],{"class":293},[49,1489,423],{"class":94},[49,1491,1492,1494,1497,1499,1502],{"class":51,"line":160},[49,1493,442],{"class":293},[49,1495,1496],{"class":94}," strings.",[49,1498,1436],{"class":62},[49,1500,1501],{"class":94},"(s, sub)  ",[49,1503,1504],{"class":55},"\u002F\u002F 0 allocations\n",[49,1506,1507],{"class":51,"line":177},[49,1508,450],{"class":94},[49,1510,1511],{"class":51,"line":184},[49,1512,181],{"emptyLinePlaceholder":180},[49,1514,1515],{"class":51,"line":190},[49,1516,1517],{"class":55},"\u002F\u002F ✅ For zero-copy (Go 1.20+, advanced — only for read-only):\n",[49,1519,1520],{"class":51,"line":202},[49,1521,1522],{"class":55},"\u002F\u002F import \"unsafe\"\n",[49,1524,1525,1528],{"class":51,"line":214},[49,1526,1527],{"class":55},"\u002F\u002F b := unsafe.Slice(unsafe.StringData(s), len(s))",[49,1529,1530],{"class":55},"  \u002F\u002F []byte sharing s's memory\n",[49,1532,1533],{"class":51,"line":228},[49,1534,1535],{"class":55},"\u002F\u002F ⚠️ Never modify b — corrupts the read-only string table.\n",[258,1537,1539],{"id":1538},"_5-pass-large-structs-by-pointer","5. Pass large structs by pointer",[19,1541,1542,1666,1670],{"language":63},[23,1543,1545],{"className":268,"code":1544,"language":63,"meta":28,"style":28},"\u002F\u002F ❌ Copies the whole struct on every call:\nfunc processBig(b BigStruct) error {  \u002F\u002F ~200 bytes copied\n    _ = b\n    return nil\n}\n\n\u002F\u002F ✅ Pointer — no copy:\nfunc processBigGood(b *BigStruct) error {  \u002F\u002F 8 bytes (pointer)\n    _ = b\n    return nil\n}\n\n\u002F\u002F ⚠️ For small structs (≤ 64 bytes), the value copy is cheaper than\n\u002F\u002F the pointer indirection. Benchmark to decide.\n",[30,1546,1547,1552,1578,1588,1595,1599,1603,1608,1634,1642,1648,1652,1656,1661],{"__ignoreMap":28},[49,1548,1549],{"class":51,"line":52},[49,1550,1551],{"class":55},"\u002F\u002F ❌ Copies the whole struct on every call:\n",[49,1553,1554,1556,1559,1561,1564,1567,1569,1572,1575],{"class":51,"line":59},[49,1555,411],{"class":293},[49,1557,1558],{"class":62}," processBig",[49,1560,95],{"class":94},[49,1562,1563],{"class":752},"b",[49,1565,1566],{"class":62}," BigStruct",[49,1568,100],{"class":94},[49,1570,1571],{"class":293},"error",[49,1573,1574],{"class":94}," {  ",[49,1576,1577],{"class":55},"\u002F\u002F ~200 bytes copied\n",[49,1579,1580,1583,1585],{"class":51,"line":77},[49,1581,1582],{"class":94},"    _ ",[49,1584,692],{"class":293},[49,1586,1587],{"class":94}," b\n",[49,1589,1590,1592],{"class":51,"line":91},[49,1591,442],{"class":293},[49,1593,1594],{"class":70}," nil\n",[49,1596,1597],{"class":51,"line":109},[49,1598,450],{"class":94},[49,1600,1601],{"class":51,"line":127},[49,1602,181],{"emptyLinePlaceholder":180},[49,1604,1605],{"class":51,"line":145},[49,1606,1607],{"class":55},"\u002F\u002F ✅ Pointer — no copy:\n",[49,1609,1610,1612,1615,1617,1619,1622,1625,1627,1629,1631],{"class":51,"line":160},[49,1611,411],{"class":293},[49,1613,1614],{"class":62}," processBigGood",[49,1616,95],{"class":94},[49,1618,1563],{"class":752},[49,1620,1621],{"class":293}," *",[49,1623,1624],{"class":62},"BigStruct",[49,1626,100],{"class":94},[49,1628,1571],{"class":293},[49,1630,1574],{"class":94},[49,1632,1633],{"class":55},"\u002F\u002F 8 bytes (pointer)\n",[49,1635,1636,1638,1640],{"class":51,"line":177},[49,1637,1582],{"class":94},[49,1639,692],{"class":293},[49,1641,1587],{"class":94},[49,1643,1644,1646],{"class":51,"line":184},[49,1645,442],{"class":293},[49,1647,1594],{"class":70},[49,1649,1650],{"class":51,"line":190},[49,1651,450],{"class":94},[49,1653,1654],{"class":51,"line":202},[49,1655,181],{"emptyLinePlaceholder":180},[49,1657,1658],{"class":51,"line":214},[49,1659,1660],{"class":55},"\u002F\u002F ⚠️ For small structs (≤ 64 bytes), the value copy is cheaper than\n",[49,1662,1663],{"class":51,"line":228},[49,1664,1665],{"class":55},"\u002F\u002F the pointer indirection. Benchmark to decide.\n",[14,1667,1669],{"id":1668},"benchmarking-allocation-reduction","Benchmarking Allocation Reduction",[19,1671,1672,2006,2010],{"language":63},[23,1673,1675],{"className":268,"code":1674,"language":63,"meta":28,"style":28},"package main\n\nimport \"testing\"\n\nfunc BenchmarkBadConcat(b *testing.B) {\n    b.ReportAllocs()\n    words := []string{\"a\", \"b\", \"c\", \"d\", \"e\"}\n    for n := 0; n \u003C b.N; n++ {\n        s := \"\"\n        for _, w := range words {\n            s += w\n        }\n        _ = s\n    }\n}\n\u002F\u002F Result: ~5 allocs\u002Fop, ~80 B\u002Fop\n\nfunc BenchmarkGoodConcat(b *testing.B) {\n    b.ReportAllocs()\n    words := []string{\"a\", \"b\", \"c\", \"d\", \"e\"}\n    for n := 0; n \u003C b.N; n++ {\n        var b strings.Builder\n        for _, w := range words {\n            b.WriteString(w)\n        }\n        _ = b.String()\n    }\n}\n\u002F\u002F Result: 1 alloc\u002Fop, ~32 B\u002Fop — 5x fewer allocations\n",[30,1676,1677,1685,1689,1703,1707,1730,1739,1778,1801,1809,1822,1832,1837,1845,1849,1853,1858,1862,1883,1891,1923,1943,1956,1968,1977,1981,1993,1997,2001],{"__ignoreMap":28},[49,1678,1679,1682],{"class":51,"line":52},[49,1680,1681],{"class":293},"package",[49,1683,1684],{"class":62}," main\n",[49,1686,1687],{"class":51,"line":59},[49,1688,181],{"emptyLinePlaceholder":180},[49,1690,1691,1694,1697,1700],{"class":51,"line":77},[49,1692,1693],{"class":293},"import",[49,1695,1696],{"class":66}," \"",[49,1698,1699],{"class":62},"testing",[49,1701,1702],{"class":66},"\"\n",[49,1704,1705],{"class":51,"line":91},[49,1706,181],{"emptyLinePlaceholder":180},[49,1708,1709,1711,1714,1716,1718,1720,1722,1724,1727],{"class":51,"line":109},[49,1710,411],{"class":293},[49,1712,1713],{"class":62}," BenchmarkBadConcat",[49,1715,95],{"class":94},[49,1717,1563],{"class":752},[49,1719,1621],{"class":293},[49,1721,1699],{"class":62},[49,1723,862],{"class":94},[49,1725,1726],{"class":62},"B",[49,1728,1729],{"class":94},") {\n",[49,1731,1732,1734,1737],{"class":51,"line":127},[49,1733,870],{"class":94},[49,1735,1736],{"class":62},"ReportAllocs",[49,1738,1365],{"class":94},[49,1740,1741,1744,1746,1748,1750,1753,1756,1758,1761,1763,1766,1768,1771,1773,1776],{"class":51,"line":145},[49,1742,1743],{"class":94},"    words ",[49,1745,431],{"class":293},[49,1747,756],{"class":94},[49,1749,759],{"class":293},[49,1751,1752],{"class":94},"{",[49,1754,1755],{"class":66},"\"a\"",[49,1757,321],{"class":94},[49,1759,1760],{"class":66},"\"b\"",[49,1762,321],{"class":94},[49,1764,1765],{"class":66},"\"c\"",[49,1767,321],{"class":94},[49,1769,1770],{"class":66},"\"d\"",[49,1772,321],{"class":94},[49,1774,1775],{"class":66},"\"e\"",[49,1777,450],{"class":94},[49,1779,1780,1782,1785,1787,1789,1792,1794,1797,1799],{"class":51,"line":160},[49,1781,595],{"class":293},[49,1783,1784],{"class":94}," n ",[49,1786,431],{"class":293},[49,1788,602],{"class":70},[49,1790,1791],{"class":94},"; n ",[49,1793,608],{"class":293},[49,1795,1796],{"class":94}," b.N; n",[49,1798,617],{"class":293},[49,1800,423],{"class":94},[49,1802,1803,1805,1807],{"class":51,"line":177},[49,1804,795],{"class":94},[49,1806,431],{"class":293},[49,1808,775],{"class":66},[49,1810,1811,1814,1816,1818,1820],{"class":51,"line":184},[49,1812,1813],{"class":293},"        for",[49,1815,782],{"class":94},[49,1817,431],{"class":293},[49,1819,787],{"class":293},[49,1821,790],{"class":94},[49,1823,1824,1827,1829],{"class":51,"line":190},[49,1825,1826],{"class":94},"            s ",[49,1828,798],{"class":293},[49,1830,1831],{"class":94}," w\n",[49,1833,1834],{"class":51,"line":202},[49,1835,1836],{"class":94},"        }\n",[49,1838,1839,1841,1843],{"class":51,"line":214},[49,1840,689],{"class":94},[49,1842,692],{"class":293},[49,1844,815],{"class":94},[49,1846,1847],{"class":51,"line":228},[49,1848,639],{"class":94},[49,1850,1851],{"class":51,"line":233},[49,1852,450],{"class":94},[49,1854,1855],{"class":51,"line":239},[49,1856,1857],{"class":55},"\u002F\u002F Result: ~5 allocs\u002Fop, ~80 B\u002Fop\n",[49,1859,1860],{"class":51,"line":253},[49,1861,181],{"emptyLinePlaceholder":180},[49,1863,1864,1866,1869,1871,1873,1875,1877,1879,1881],{"class":51,"line":508},[49,1865,411],{"class":293},[49,1867,1868],{"class":62}," BenchmarkGoodConcat",[49,1870,95],{"class":94},[49,1872,1563],{"class":752},[49,1874,1621],{"class":293},[49,1876,1699],{"class":62},[49,1878,862],{"class":94},[49,1880,1726],{"class":62},[49,1882,1729],{"class":94},[49,1884,1885,1887,1889],{"class":51,"line":514},[49,1886,870],{"class":94},[49,1888,1736],{"class":62},[49,1890,1365],{"class":94},[49,1892,1893,1895,1897,1899,1901,1903,1905,1907,1909,1911,1913,1915,1917,1919,1921],{"class":51,"line":524},[49,1894,1743],{"class":94},[49,1896,431],{"class":293},[49,1898,756],{"class":94},[49,1900,759],{"class":293},[49,1902,1752],{"class":94},[49,1904,1755],{"class":66},[49,1906,321],{"class":94},[49,1908,1760],{"class":66},[49,1910,321],{"class":94},[49,1912,1765],{"class":66},[49,1914,321],{"class":94},[49,1916,1770],{"class":66},[49,1918,321],{"class":94},[49,1920,1775],{"class":66},[49,1922,450],{"class":94},[49,1924,1925,1927,1929,1931,1933,1935,1937,1939,1941],{"class":51,"line":534},[49,1926,595],{"class":293},[49,1928,1784],{"class":94},[49,1930,431],{"class":293},[49,1932,602],{"class":70},[49,1934,1791],{"class":94},[49,1936,608],{"class":293},[49,1938,1796],{"class":94},[49,1940,617],{"class":293},[49,1942,423],{"class":94},[49,1944,1945,1948,1950,1952,1954],{"class":51,"line":555},[49,1946,1947],{"class":293},"        var",[49,1949,856],{"class":94},[49,1951,859],{"class":62},[49,1953,862],{"class":94},[49,1955,865],{"class":62},[49,1957,1958,1960,1962,1964,1966],{"class":51,"line":566},[49,1959,1813],{"class":293},[49,1961,782],{"class":94},[49,1963,431],{"class":293},[49,1965,787],{"class":293},[49,1967,790],{"class":94},[49,1969,1970,1973,1975],{"class":51,"line":571},[49,1971,1972],{"class":94},"            b.",[49,1974,904],{"class":62},[49,1976,907],{"class":94},[49,1978,1979],{"class":51,"line":576},[49,1980,1836],{"class":94},[49,1982,1983,1985,1987,1989,1991],{"class":51,"line":582},[49,1984,689],{"class":94},[49,1986,692],{"class":293},[49,1988,918],{"class":94},[49,1990,921],{"class":62},[49,1992,1365],{"class":94},[49,1994,1995],{"class":51,"line":592},[49,1996,639],{"class":94},[49,1998,1999],{"class":51,"line":622},[49,2000,450],{"class":94},[49,2002,2003],{"class":51,"line":636},[49,2004,2005],{"class":55},"\u002F\u002F Result: 1 alloc\u002Fop, ~32 B\u002Fop — 5x fewer allocations\n",[14,2007,2009],{"id":2008},"inlining-when-the-compiler-optimizes","Inlining — When the Compiler Optimizes",[19,2011,2012,2274,2278],{"language":63},[23,2013,2015],{"className":268,"code":2014,"language":63,"meta":28,"style":28},"\u002F\u002F The Go inliner copies small function bodies into the call site,\n\u002F\u002F eliminating the function call overhead.\n\n\u002F\u002F ✅ Small, leaf functions are inlined automatically:\nfunc max(a, b int) int {\n    if a > b { return a }\n    return b\n}\n\u002F\u002F The compiler inlines this — no function call at runtime.\n\n\u002F\u002F ❌ Functions with complex bodies are NOT inlined:\nfunc complex(n int) int {\n    for i := 0; i \u003C n; i++ {  \u002F\u002F loops prevent inlining\n        n += i\n    }\n    return n\n}\n\n\u002F\u002F Check inlining decisions:\n\u002F\u002F go build -gcflags='-m' .\u002F...\n\u002F\u002F Output:\n\u002F\u002F   .\u002Fmain.go:5:6: can inline max\n\u002F\u002F   .\u002Fmain.go:10:6: cannot inline complex: function too complex\n\n\u002F\u002F ⚠️ Defer with a function value prevents inlining:\n\u002F\u002F func f() { defer fmt.Println(\"done\") }  \u002F\u002F fmt.Println is a value — no inline\n\u002F\u002F func f() { defer func() { fmt.Println(\"done\") }() }  \u002F\u002F anonymous — may inline\n\n\u002F\u002F Force inlining (advanced — rarely needed):\n\u002F\u002Fgo:inline\nfunc hotPath(x int) int { return x * 2 }\n",[30,2016,2017,2022,2027,2031,2036,2061,2080,2086,2090,2095,2099,2104,2124,2148,2158,2162,2169,2173,2177,2182,2187,2192,2197,2202,2206,2211,2219,2227,2231,2236,2241],{"__ignoreMap":28},[49,2018,2019],{"class":51,"line":52},[49,2020,2021],{"class":55},"\u002F\u002F The Go inliner copies small function bodies into the call site,\n",[49,2023,2024],{"class":51,"line":59},[49,2025,2026],{"class":55},"\u002F\u002F eliminating the function call overhead.\n",[49,2028,2029],{"class":51,"line":77},[49,2030,181],{"emptyLinePlaceholder":180},[49,2032,2033],{"class":51,"line":91},[49,2034,2035],{"class":55},"\u002F\u002F ✅ Small, leaf functions are inlined automatically:\n",[49,2037,2038,2040,2043,2045,2048,2050,2052,2055,2057,2059],{"class":51,"line":109},[49,2039,411],{"class":293},[49,2041,2042],{"class":62}," max",[49,2044,95],{"class":94},[49,2046,2047],{"class":752},"a",[49,2049,321],{"class":94},[49,2051,1563],{"class":752},[49,2053,2054],{"class":293}," int",[49,2056,100],{"class":94},[49,2058,420],{"class":293},[49,2060,423],{"class":94},[49,2062,2063,2066,2069,2072,2075,2077],{"class":51,"line":127},[49,2064,2065],{"class":293},"    if",[49,2067,2068],{"class":94}," a ",[49,2070,2071],{"class":293},">",[49,2073,2074],{"class":94}," b { ",[49,2076,1228],{"class":293},[49,2078,2079],{"class":94}," a }\n",[49,2081,2082,2084],{"class":51,"line":145},[49,2083,442],{"class":293},[49,2085,1587],{"class":94},[49,2087,2088],{"class":51,"line":160},[49,2089,450],{"class":94},[49,2091,2092],{"class":51,"line":177},[49,2093,2094],{"class":55},"\u002F\u002F The compiler inlines this — no function call at runtime.\n",[49,2096,2097],{"class":51,"line":184},[49,2098,181],{"emptyLinePlaceholder":180},[49,2100,2101],{"class":51,"line":190},[49,2102,2103],{"class":55},"\u002F\u002F ❌ Functions with complex bodies are NOT inlined:\n",[49,2105,2106,2108,2111,2113,2116,2118,2120,2122],{"class":51,"line":202},[49,2107,411],{"class":293},[49,2109,2110],{"class":62}," complex",[49,2112,95],{"class":94},[49,2114,2115],{"class":752},"n",[49,2117,2054],{"class":293},[49,2119,100],{"class":94},[49,2121,420],{"class":293},[49,2123,423],{"class":94},[49,2125,2126,2128,2130,2132,2134,2136,2138,2141,2143,2145],{"class":51,"line":214},[49,2127,595],{"class":293},[49,2129,540],{"class":94},[49,2131,431],{"class":293},[49,2133,602],{"class":70},[49,2135,605],{"class":94},[49,2137,608],{"class":293},[49,2139,2140],{"class":94}," n; i",[49,2142,617],{"class":293},[49,2144,1574],{"class":94},[49,2146,2147],{"class":55},"\u002F\u002F loops prevent inlining\n",[49,2149,2150,2153,2155],{"class":51,"line":228},[49,2151,2152],{"class":94},"        n ",[49,2154,798],{"class":293},[49,2156,2157],{"class":94}," i\n",[49,2159,2160],{"class":51,"line":233},[49,2161,639],{"class":94},[49,2163,2164,2166],{"class":51,"line":239},[49,2165,442],{"class":293},[49,2167,2168],{"class":94}," n\n",[49,2170,2171],{"class":51,"line":253},[49,2172,450],{"class":94},[49,2174,2175],{"class":51,"line":508},[49,2176,181],{"emptyLinePlaceholder":180},[49,2178,2179],{"class":51,"line":514},[49,2180,2181],{"class":55},"\u002F\u002F Check inlining decisions:\n",[49,2183,2184],{"class":51,"line":524},[49,2185,2186],{"class":55},"\u002F\u002F go build -gcflags='-m' .\u002F...\n",[49,2188,2189],{"class":51,"line":534},[49,2190,2191],{"class":55},"\u002F\u002F Output:\n",[49,2193,2194],{"class":51,"line":555},[49,2195,2196],{"class":55},"\u002F\u002F   .\u002Fmain.go:5:6: can inline max\n",[49,2198,2199],{"class":51,"line":566},[49,2200,2201],{"class":55},"\u002F\u002F   .\u002Fmain.go:10:6: cannot inline complex: function too complex\n",[49,2203,2204],{"class":51,"line":571},[49,2205,181],{"emptyLinePlaceholder":180},[49,2207,2208],{"class":51,"line":576},[49,2209,2210],{"class":55},"\u002F\u002F ⚠️ Defer with a function value prevents inlining:\n",[49,2212,2213,2216],{"class":51,"line":582},[49,2214,2215],{"class":55},"\u002F\u002F func f() { defer fmt.Println(\"done\") }",[49,2217,2218],{"class":55},"  \u002F\u002F fmt.Println is a value — no inline\n",[49,2220,2221,2224],{"class":51,"line":592},[49,2222,2223],{"class":55},"\u002F\u002F func f() { defer func() { fmt.Println(\"done\") }() }",[49,2225,2226],{"class":55},"  \u002F\u002F anonymous — may inline\n",[49,2228,2229],{"class":51,"line":622},[49,2230,181],{"emptyLinePlaceholder":180},[49,2232,2233],{"class":51,"line":636},[49,2234,2235],{"class":55},"\u002F\u002F Force inlining (advanced — rarely needed):\n",[49,2237,2238],{"class":51,"line":642},[49,2239,2240],{"class":55},"\u002F\u002Fgo:inline\n",[49,2242,2243,2245,2248,2250,2253,2255,2257,2259,2261,2263,2266,2268,2271],{"class":51,"line":647},[49,2244,411],{"class":293},[49,2246,2247],{"class":62}," hotPath",[49,2249,95],{"class":94},[49,2251,2252],{"class":752},"x",[49,2254,2054],{"class":293},[49,2256,100],{"class":94},[49,2258,420],{"class":293},[49,2260,1225],{"class":94},[49,2262,1228],{"class":293},[49,2264,2265],{"class":94}," x ",[49,2267,1294],{"class":293},[49,2269,2270],{"class":70}," 2",[49,2272,2273],{"class":94}," }\n",[14,2275,2277],{"id":2276},"memory-leaks-detection","Memory Leaks — Detection",[19,2279,2280,2445,2449,2539,2543,2662,2666],{"language":63},[23,2281,2283],{"className":268,"code":2282,"language":63,"meta":28,"style":28},"\u002F\u002F Go has a GC, but memory leaks still happen:\n\u002F\u002F   - Goroutine leaks (blocked goroutines holding references)\n\u002F\u002F   - Growing maps\u002Fslices never freed\n\u002F\u002F   - Closures capturing large variables\n\n\u002F\u002F Detect with pprof heap over time:\n\u002F\u002F 1. Take a heap snapshot:\ncurl http:\u002F\u002Flocalhost:6060\u002Fdebug\u002Fpprof\u002Fheap > heap1.out\n\u002F\u002F 2. Wait (or send load):\nsleep 60\n\u002F\u002F 3. Take another snapshot:\ncurl http:\u002F\u002Flocalhost:6060\u002Fdebug\u002Fpprof\u002Fheap > heap2.out\n\u002F\u002F 4. Compare:\ngo tool pprof -base=heap1.out heap2.out\n(pprof) top  # shows what grew between snapshots\n\n\u002F\u002F ─── Common leak: growing map ───\ntype Cache struct {\n    mu    sync.Mutex\n    items map[string]*Item  \u002F\u002F never deleted → grows forever\n}\n\u002F\u002F Fix: add TTL-based eviction or a max size with LRU.\n",[30,2284,2285,2290,2295,2300,2305,2309,2314,2319,2327,2332,2340,2345,2352,2357,2375,2380,2384,2389,2402,2415,2436,2440],{"__ignoreMap":28},[49,2286,2287],{"class":51,"line":52},[49,2288,2289],{"class":55},"\u002F\u002F Go has a GC, but memory leaks still happen:\n",[49,2291,2292],{"class":51,"line":59},[49,2293,2294],{"class":55},"\u002F\u002F   - Goroutine leaks (blocked goroutines holding references)\n",[49,2296,2297],{"class":51,"line":77},[49,2298,2299],{"class":55},"\u002F\u002F   - Growing maps\u002Fslices never freed\n",[49,2301,2302],{"class":51,"line":91},[49,2303,2304],{"class":55},"\u002F\u002F   - Closures capturing large variables\n",[49,2306,2307],{"class":51,"line":109},[49,2308,181],{"emptyLinePlaceholder":180},[49,2310,2311],{"class":51,"line":127},[49,2312,2313],{"class":55},"\u002F\u002F Detect with pprof heap over time:\n",[49,2315,2316],{"class":51,"line":145},[49,2317,2318],{"class":55},"\u002F\u002F 1. Take a heap snapshot:\n",[49,2320,2321,2324],{"class":51,"line":160},[49,2322,2323],{"class":94},"curl http:",[49,2325,2326],{"class":55},"\u002F\u002Flocalhost:6060\u002Fdebug\u002Fpprof\u002Fheap > heap1.out\n",[49,2328,2329],{"class":51,"line":177},[49,2330,2331],{"class":55},"\u002F\u002F 2. Wait (or send load):\n",[49,2333,2334,2337],{"class":51,"line":184},[49,2335,2336],{"class":94},"sleep ",[49,2338,2339],{"class":70},"60\n",[49,2341,2342],{"class":51,"line":190},[49,2343,2344],{"class":55},"\u002F\u002F 3. Take another snapshot:\n",[49,2346,2347,2349],{"class":51,"line":202},[49,2348,2323],{"class":94},[49,2350,2351],{"class":55},"\u002F\u002Flocalhost:6060\u002Fdebug\u002Fpprof\u002Fheap > heap2.out\n",[49,2353,2354],{"class":51,"line":214},[49,2355,2356],{"class":55},"\u002F\u002F 4. Compare:\n",[49,2358,2359,2361,2364,2367,2370,2372],{"class":51,"line":228},[49,2360,63],{"class":293},[49,2362,2363],{"class":94}," tool pprof ",[49,2365,2366],{"class":293},"-",[49,2368,2369],{"class":94},"base",[49,2371,692],{"class":293},[49,2373,2374],{"class":94},"heap1.out heap2.out\n",[49,2376,2377],{"class":51,"line":233},[49,2378,2379],{"class":94},"(pprof) top  # shows what grew between snapshots\n",[49,2381,2382],{"class":51,"line":239},[49,2383,181],{"emptyLinePlaceholder":180},[49,2385,2386],{"class":51,"line":253},[49,2387,2388],{"class":55},"\u002F\u002F ─── Common leak: growing map ───\n",[49,2390,2391,2394,2397,2400],{"class":51,"line":508},[49,2392,2393],{"class":293},"type",[49,2395,2396],{"class":62}," Cache",[49,2398,2399],{"class":293}," struct",[49,2401,423],{"class":94},[49,2403,2404,2407,2410,2412],{"class":51,"line":514},[49,2405,2406],{"class":94},"    mu    ",[49,2408,2409],{"class":62},"sync",[49,2411,862],{"class":94},[49,2413,2414],{"class":62},"Mutex\n",[49,2416,2417,2420,2422,2424,2426,2428,2430,2433],{"class":51,"line":524},[49,2418,2419],{"class":94},"    items ",[49,2421,1155],{"class":293},[49,2423,1158],{"class":94},[49,2425,759],{"class":293},[49,2427,1163],{"class":94},[49,2429,1294],{"class":293},[49,2431,2432],{"class":62},"Item",[49,2434,2435],{"class":55},"  \u002F\u002F never deleted → grows forever\n",[49,2437,2438],{"class":51,"line":534},[49,2439,450],{"class":94},[49,2441,2442],{"class":51,"line":555},[49,2443,2444],{"class":55},"\u002F\u002F Fix: add TTL-based eviction or a max size with LRU.\n",[14,2446,2448],{"id":2447},"tips-tricks","💡 Tips & Tricks",[2450,2451,2452,2469,2490,2503,2510,2518],"ul",{},[2453,2454,2455,2459,2460,2463,2464,321,2466,2468],"li",{},[2456,2457,2458],"strong",{},"Performance",": ",[30,2461,2462],{},"allocs\u002Fop"," is the key benchmark metric — heap allocations trigger GC. Reducing allocations (pre-allocate, ",[30,2465,724],{},[30,2467,1182],{},") often improves performance more than micro-optimizing CPU.",[2453,2470,2471,2474,2475,2477,2478,2481,2482,2485,2486,2489],{},[2456,2472,2473],{},"Idiom",": use ",[30,2476,724],{}," with ",[30,2479,2480],{},"Grow(total)"," for string concatenation — ",[30,2483,2484],{},"s += w"," in a loop is O(n²); ",[30,2487,2488],{},"Builder"," is O(n). Pre-grow with the estimated total size to avoid reallocations.",[2453,2491,2492,2494,2495,2498,2499,2502],{},[2456,2493,2473],{},": pre-allocate slices and maps when you know the size — ",[30,2496,2497],{},"make([]T, 0, n)"," and ",[30,2500,2501],{},"make(map[K]V, n)"," avoid incremental growth\u002Frehashing.",[2453,2504,2505,2474,2507,2509],{},[2456,2506,2473],{},[30,2508,1182],{}," for short-lived, allocation-heavy objects (buffers, temp structs) — reset before Put. Don't store long-lived state (pool objects can be reclaimed between GCs).",[2453,2511,2512,2459,2514,2517],{},[2456,2513,2458],{},[30,2515,2516],{},"go build -gcflags='-m'"," shows escape analysis — tells you which variables escape to the heap. In hot paths, eliminating escapes (keeping values on the stack) is the #1 allocation-reduction technique.",[2453,2519,2520,2522,2523,2526,2527,2530,2531,2534,2535,2538],{},[2456,2521,2458],{},": avoid ",[30,2524,2525],{},"fmt"," in hot paths — ",[30,2528,2529],{},"fmt.Println"," takes ",[30,2532,2533],{},"...any",", causing every argument to escape to the heap (interface boxing). Use ",[30,2536,2537],{},"strconv"," or direct writes.",[14,2540,2542],{"id":2541},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[2450,2544,2545,2554,2578,2596,2606,2619,2632,2644,2652],{},[2453,2546,2547,2550,2551,2553],{},[2456,2548,2549],{},"Premature optimization",": always profile first. A function at 1% of CPU isn't worth optimizing — the top consumer is. ",[30,2552,37],{}," shows you where to focus.",[2453,2555,2556,2459,2561,2564,2565,2567,2568,2570,2571,2574,2575,862],{},[2456,2557,2558,2560],{},[30,2559,2529],{}," causes escapes",[30,2562,2563],{},"fmt.Println(x)"," boxes ",[30,2566,2252],{}," into ",[30,2569,543],{}," → heap allocation. In hot paths, use ",[30,2572,2573],{},"strconv.Itoa"," or ",[30,2576,2577],{},"os.Stdout.Write",[2453,2579,2580,2586,2587,2589,2590,2592,2593,2595],{},[2456,2581,2582,2585],{},[30,2583,2584],{},"[]byte(s)"," allocates",": string ↔ ",[30,2588,1381],{}," conversion copies the data (strings are immutable). Use ",[30,2591,859],{},"\u002F",[30,2594,1236],{}," package functions that work on the native type.",[2453,2597,2598,2601,2602,2605],{},[2456,2599,2600],{},"Defer prevents inlining",": a function with ",[30,2603,2604],{},"defer"," may not be inlined (the defer overhead must be set up). In ultra-hot paths, avoid defer.",[2453,2607,2608,2614,2615,2618],{},[2456,2609,2610,2613],{},[30,2611,2612],{},"runtime.GC()"," doesn't help in production",": manually triggering GC adds pauses. Let the concurrent GC run — tune with ",[30,2616,2617],{},"GOGC"," (default 100 = GC when heap doubles).",[2453,2620,2621,2627,2628,2631],{},[2456,2622,2623,2626],{},[30,2624,2625],{},"GOGC=50"," reduces memory but increases CPU",": the GC runs more often (when heap grows 50% instead of 100%). Trade memory for CPU. Use ",[30,2629,2630],{},"GOMEMLIMIT"," (Go 1.19+) for a hard memory cap instead.",[2453,2633,2634,2639,2640,2643],{},[2456,2635,2636,2638],{},[30,2637,37],{}," overhead",": profiling adds ~2x overhead. Run it in production briefly (30s), not continuously. Use ",[30,2641,2642],{},"runtime.SetCPUProfileRate"," for fine control.",[2453,2645,2646,2651],{},[2456,2647,2648],{},[30,2649,2650],{},"runtime.SetBlockProfileRate(n)",": enables blocking profile — records goroutine blocking (channel, mutex, syscall). n=1 samples every blocking event (expensive); n=10000 samples every 10µs.",[2453,2653,2654,2657,2658,2661],{},[2456,2655,2656],{},"Inlining has limits",": functions with loops, switches, or too many statements aren't inlined. The threshold is tunable via ",[30,2659,2660],{},"-gcflags='-l=4'"," (higher = more aggressive).",[14,2663,2665],{"id":2664},"quick-quiz","🧠 Quick Quiz",[19,2667,2668,2768],{"language":63},[23,2669,2671],{"className":268,"code":2670,"language":63,"meta":28,"style":28},"func A(b *bytes.Buffer) {\n    b.WriteString(\"hello\")\n}\n\nfunc B() string {\n    var b bytes.Buffer\n    A(&b)\n    return b.String()\n}\n",[30,2672,2673,2694,2707,2711,2715,2728,2741,2754,2764],{"__ignoreMap":28},[49,2674,2675,2677,2680,2682,2684,2686,2688,2690,2692],{"class":51,"line":52},[49,2676,411],{"class":293},[49,2678,2679],{"class":62}," A",[49,2681,95],{"class":94},[49,2683,1563],{"class":752},[49,2685,1621],{"class":293},[49,2687,1236],{"class":62},[49,2689,862],{"class":94},[49,2691,1241],{"class":62},[49,2693,1729],{"class":94},[49,2695,2696,2698,2700,2702,2705],{"class":51,"line":59},[49,2697,870],{"class":94},[49,2699,904],{"class":62},[49,2701,95],{"class":94},[49,2703,2704],{"class":66},"\"hello\"",[49,2706,1303],{"class":94},[49,2708,2709],{"class":51,"line":77},[49,2710,450],{"class":94},[49,2712,2713],{"class":51,"line":91},[49,2714,181],{"emptyLinePlaceholder":180},[49,2716,2717,2719,2722,2724,2726],{"class":51,"line":109},[49,2718,411],{"class":293},[49,2720,2721],{"class":62}," B",[49,2723,417],{"class":94},[49,2725,759],{"class":293},[49,2727,423],{"class":94},[49,2729,2730,2732,2734,2736,2738],{"class":51,"line":127},[49,2731,537],{"class":293},[49,2733,856],{"class":94},[49,2735,1236],{"class":62},[49,2737,862],{"class":94},[49,2739,2740],{"class":62},"Buffer\n",[49,2742,2743,2746,2748,2751],{"class":51,"line":145},[49,2744,2745],{"class":62},"    A",[49,2747,95],{"class":94},[49,2749,2750],{"class":293},"&",[49,2752,2753],{"class":94},"b)\n",[49,2755,2756,2758,2760,2762],{"class":51,"line":160},[49,2757,442],{"class":293},[49,2759,918],{"class":94},[49,2761,921],{"class":62},[49,2763,1365],{"class":94},[49,2765,2766],{"class":51,"line":177},[49,2767,450],{"class":94},[2769,2770,2771,2772,2774,2775,2778],"p",{},"Does ",[30,2773,1563],{}," in ",[30,2776,2777],{},"B()"," escape to the heap?",[2780,2781,2782,2786,2794,2814,2817,2848,2864],"details",{},[2783,2784,2785],"summary",{},"Answer",[2769,2787,2788,321,2791,2793],{},[2456,2789,2790],{},"Yes",[30,2792,1563],{}," escapes to the heap.",[2769,2795,2796,2799,2800,2803,2804,2807,2808,2810,2811,2813],{},[30,2797,2798],{},"A(&b)"," passes ",[30,2801,2802],{},"&b"," to another function. The compiler can't prove that ",[30,2805,2806],{},"A"," doesn't store the pointer somewhere (in a global, a channel, a struct that outlives ",[30,2809,1726],{},"). To be safe, escape analysis moves ",[30,2812,1563],{}," to the heap.",[2769,2815,2816],{},"Verify:",[23,2818,2820],{"className":44,"code":2819,"language":41,"meta":28,"style":28},"go build -gcflags='-m' main.go\n# .\u002Fmain.go:5:6: moved to heap: b\n# .\u002Fmain.go:6:7: &b escapes to heap\n",[30,2821,2822,2838,2843],{"__ignoreMap":28},[49,2823,2824,2826,2829,2832,2835],{"class":51,"line":52},[49,2825,63],{"class":62},[49,2827,2828],{"class":66}," build",[49,2830,2831],{"class":70}," -gcflags=",[49,2833,2834],{"class":66},"'-m'",[49,2836,2837],{"class":66}," main.go\n",[49,2839,2840],{"class":51,"line":59},[49,2841,2842],{"class":55},"# .\u002Fmain.go:5:6: moved to heap: b\n",[49,2844,2845],{"class":51,"line":77},[49,2846,2847],{"class":55},"# .\u002Fmain.go:6:7: &b escapes to heap\n",[2769,2849,2850,2851,2853,2854,2856,2857,2859,2860,2863],{},"If ",[30,2852,2806],{}," were inlined (small enough), the compiler might see that ",[30,2855,2802],{}," doesn't escape and keep ",[30,2858,1563],{}," on the stack. But ",[30,2861,2862],{},"bytes.Buffer.WriteString"," is a method call that the compiler may not inline, so the escape analysis is conservative.",[2769,2865,2866,2867,2869],{},"In hot paths, if you know the buffer doesn't escape, you can use ",[30,2868,1182],{}," to reuse heap-allocated buffers (the pool manages the heap allocation, amortized across calls).",[14,2871,2873],{"id":2872},"whats-next","📚 What's Next",[2769,2875,2876,2877,2881],{},"→ ",[2047,2878,2880],{"href":2879},"\u002Fgo\u002F28-exercises-and-projects","28 — Exercises & Project Ideas"," — from beginner to pro, covering every chapter.",[2883,2884,2885],"style",{},"html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html.github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}html pre.shiki code .sCrzJ, html code.shiki .sCrzJ{--shiki-default:#E36209;--shiki-github-dark:#FFAB70}",{"title":28,"searchDepth":59,"depth":59,"links":2887},[2888,2889,2891],{"id":16,"depth":59,"text":17},{"id":34,"depth":59,"text":2890},"pprof — CPU and Heap Profiling",{"id":2872,"depth":59,"text":2873},"pprof CPU\u002Fheap\u002Fgoroutine profiling, escape analysis, allocation reduction, strings.Builder, sync.Pool, and benchmark-driven optimization.","md",{},"\u002Fgo\u002F27-profiling-and-performance",{"title":5,"description":2892},"go\u002F27-profiling-and-performance","QvjS4ngy9qwtx_l15WScTeA99os_isH3wxJs3La5c0c",1789924648801]