<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Go Memory Model &amp; Internals on Atharva Pandey</title><link>https://atharva.page/series/go-memory-model--internals/</link><description>Recent content in Go Memory Model &amp; Internals on Atharva Pandey</description><generator>Hugo</generator><language>en-us</language><copyright>Copyright ©</copyright><lastBuildDate>Tue, 15 Apr 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://atharva.page/series/go-memory-model--internals/index.xml" rel="self" type="application/rss+xml"/><item><title>Lesson 8: String Internals — Immutable, backed by bytes, cheaper than you think</title><link>https://atharva.page/post/go/go-internals-strings/</link><pubDate>Tue, 15 Apr 2025 00:00:00 +0000</pubDate><guid>https://atharva.page/post/go/go-internals-strings/</guid><description>&lt;p&gt;I used to reach for &lt;code&gt;[]byte&lt;/code&gt; over &lt;code&gt;string&lt;/code&gt; in performance-sensitive code, assuming strings were somehow more expensive because &amp;ldquo;immutability must cost something.&amp;rdquo; That intuition was wrong. Understanding what a string actually is — a read-only slice header — corrected my assumptions and simplified a lot of code I had unnecessarily complicated.&lt;/p&gt;
&lt;h2 id="the-problem"&gt;The Problem&lt;/h2&gt;
&lt;p&gt;Strings in Go are everywhere, and most developers use them without thinking about what they are at the memory level. This leads to a few common mistakes:&lt;/p&gt;</description></item><item><title>Lesson 7: Values Copy vs Share — When Go copies and when it doesn't</title><link>https://atharva.page/post/go/go-internals-copy-share/</link><pubDate>Sat, 01 Mar 2025 00:00:00 +0000</pubDate><guid>https://atharva.page/post/go/go-internals-copy-share/</guid><description>&lt;p&gt;Early in my Go career I had a bug where I modified a slice inside a function expecting the caller&amp;rsquo;s slice to remain unchanged — and it did. Then I had a different bug where I expected the opposite and the caller&amp;rsquo;s slice &lt;em&gt;was&lt;/em&gt; modified. I had no mental model for predicting which would happen. Building that model is what this lesson is about.&lt;/p&gt;
&lt;h2 id="the-problem"&gt;The Problem&lt;/h2&gt;
&lt;p&gt;Go passes everything by value. That&amp;rsquo;s the official line, and it&amp;rsquo;s true. But &amp;ldquo;by value&amp;rdquo; means different things for different types:&lt;/p&gt;</description></item><item><title>Lesson 6: Memory Alignment and Struct Padding — Field order affects struct size</title><link>https://atharva.page/post/go/go-internals-alignment/</link><pubDate>Wed, 08 Jan 2025 00:00:00 +0000</pubDate><guid>https://atharva.page/post/go/go-internals-alignment/</guid><description>&lt;p&gt;I once reviewed a PR where someone had defined a struct with a bool field between two int64 fields, resulting in a 24-byte struct instead of the 17 bytes you might naively calculate. When I pointed it out, the response was &amp;ldquo;the compiler should handle that.&amp;rdquo; It doesn&amp;rsquo;t. Go respects the field order you give it, and it inserts padding to satisfy alignment requirements. Knowing the rules means you write efficient structs by default.&lt;/p&gt;</description></item><item><title>Lesson 5: GC Behavior and Tuning — GOGC and GOMEMLIMIT changed the game</title><link>https://atharva.page/post/go/go-internals-gc/</link><pubDate>Fri, 15 Nov 2024 00:00:00 +0000</pubDate><guid>https://atharva.page/post/go/go-internals-gc/</guid><description>&lt;p&gt;For years, tuning Go&amp;rsquo;s GC meant tweaking &lt;code&gt;GOGC&lt;/code&gt; and hoping for the best. I operated on vibes and guesswork. Then Go 1.19 introduced &lt;code&gt;GOMEMLIMIT&lt;/code&gt; — a hard memory limit that fundamentally changed how I reason about GC tuning. Suddenly I had a second axis of control that actually matched how production memory is constrained. This lesson is the mental model I wish I had from day one.&lt;/p&gt;
&lt;h2 id="the-problem"&gt;The Problem&lt;/h2&gt;
&lt;p&gt;Go uses a concurrent, tri-color mark-and-sweep garbage collector. &amp;ldquo;Concurrent&amp;rdquo; means most of the GC work happens while your program is running, not in stop-the-world pauses. This is generally excellent, but the GC needs to be triggered somehow, and the default trigger can be surprising.&lt;/p&gt;</description></item><item><title>Lesson 4: Escape Analysis Deep Dive — The compiler decides where your data lives</title><link>https://atharva.page/post/go/go-internals-escape-analysis/</link><pubDate>Sat, 05 Oct 2024 00:00:00 +0000</pubDate><guid>https://atharva.page/post/go/go-internals-escape-analysis/</guid><description>&lt;p&gt;I used to assume that every time I wrote &lt;code&gt;&amp;amp;someStruct{}&lt;/code&gt; or returned a pointer from a function, I was creating a heap allocation. I was wrong — and the wrongness mattered for how I was designing APIs. After learning about escape analysis, I stopped guessing and started &lt;em&gt;asking the compiler&lt;/em&gt; directly. This changed how I write Go.&lt;/p&gt;
&lt;h2 id="the-problem"&gt;The Problem&lt;/h2&gt;
&lt;p&gt;Go has two places to put data: the &lt;strong&gt;stack&lt;/strong&gt; and the &lt;strong&gt;heap&lt;/strong&gt;. Stack allocations are cheap — they&amp;rsquo;re just a pointer bump, and the stack frame is reclaimed automatically when the function returns. Heap allocations go through the memory allocator, require garbage collection, and have non-trivial overhead.&lt;/p&gt;</description></item><item><title>Lesson 3: Method Sets and Addressability — Why your value can't satisfy that interface</title><link>https://atharva.page/post/go/go-internals-method-sets/</link><pubDate>Sun, 25 Aug 2024 00:00:00 +0000</pubDate><guid>https://atharva.page/post/go/go-internals-method-sets/</guid><description>&lt;p&gt;I spent a solid twenty minutes staring at a compilation error that read &amp;ldquo;does not implement interface (Write method has pointer receiver)&amp;rdquo; and thinking: I &lt;em&gt;can see&lt;/em&gt; the Write method right there. What is Go complaining about? Once I understood method sets and why addressability matters, the rule became obvious — and I have never needed to look it up since.&lt;/p&gt;
&lt;h2 id="the-problem"&gt;The Problem&lt;/h2&gt;
&lt;p&gt;Go lets you define methods with either a value receiver or a pointer receiver:&lt;/p&gt;</description></item><item><title>Lesson 2: Nil Interface Gotchas — nil is not nil when it has a type</title><link>https://atharva.page/post/go/go-internals-nil-interface/</link><pubDate>Thu, 18 Jul 2024 00:00:00 +0000</pubDate><guid>https://atharva.page/post/go/go-internals-nil-interface/</guid><description>&lt;p&gt;A few months into my first production Go service, I had a bug that cost me two hours. A function returned an &lt;code&gt;error&lt;/code&gt;, I checked &lt;code&gt;if err != nil&lt;/code&gt; and it passed — but then further down the stack the program panicked trying to call &lt;code&gt;.Error()&lt;/code&gt; on a nil pointer. The function had returned a nil &lt;code&gt;*MyError&lt;/code&gt;, not a nil &lt;code&gt;error&lt;/code&gt;. These are not the same thing, and until you internalize why, you will hit this bug.&lt;/p&gt;</description></item><item><title>Lesson 1: Interface Representation — Two words that carry your abstractions</title><link>https://atharva.page/post/go/go-internals-interfaces/</link><pubDate>Mon, 10 Jun 2024 00:00:00 +0000</pubDate><guid>https://atharva.page/post/go/go-internals-interfaces/</guid><description>&lt;p&gt;I remember the first time I hit a bug where &lt;code&gt;err != nil&lt;/code&gt; returned &lt;code&gt;true&lt;/code&gt; even though the function clearly returned &lt;code&gt;nil&lt;/code&gt;. I spent forty minutes staring at perfectly reasonable-looking code before I realized I had no idea what an interface actually &lt;em&gt;is&lt;/em&gt; at the memory level. Once I understood the two-word representation, that class of bug never confused me again.&lt;/p&gt;
&lt;h2 id="the-problem"&gt;The Problem&lt;/h2&gt;
&lt;p&gt;Go interfaces are the backbone of polymorphism in the language. You use them constantly — &lt;code&gt;io.Reader&lt;/code&gt;, &lt;code&gt;error&lt;/code&gt;, &lt;code&gt;fmt.Stringer&lt;/code&gt;. But most developers treat them as magic. You assign a concrete value, you call methods, and somehow Go figures out which implementation to dispatch to at runtime.&lt;/p&gt;</description></item></channel></rss>