<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Lucas Padularrosa</title>
    <description>The latest articles on DEV Community by Lucas Padularrosa (@lucas_padularrosa_de2556e).</description>
    <link>https://dev.to/lucas_padularrosa_de2556e</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2466563%2Ff3effe8a-6bf4-4684-92ef-2bdac12d9ec1.jpg</url>
      <title>DEV Community: Lucas Padularrosa</title>
      <link>https://dev.to/lucas_padularrosa_de2556e</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lucas_padularrosa_de2556e"/>
    <language>en</language>
    <item>
      <title>Go Memory and Garbage Collection: What Every Developer Should Know</title>
      <dc:creator>Lucas Padularrosa</dc:creator>
      <pubDate>Fri, 10 Jul 2026 23:24:58 +0000</pubDate>
      <link>https://dev.to/lucas_padularrosa_de2556e/go-memory-and-garbage-collection-what-every-developer-should-know-4p8g</link>
      <guid>https://dev.to/lucas_padularrosa_de2556e/go-memory-and-garbage-collection-what-every-developer-should-know-4p8g</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; El GC de Go está diseñado para minimizar pausas, no allocations.&lt;br&gt;
Optimizarlo no significa tunearlo — significa darle menos trabajo.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Hay una trampa muy común cuando los developers de Go empiezan a optimizar performance: van directo a ajustar &lt;code&gt;GOGC&lt;/code&gt; o a buscar configuraciones del runtime. Están atacando el síntoma. El GC de Go tiene poco que tunear, y lo que sí podés controlar es cuánto trabajo le das.&lt;/p&gt;

&lt;p&gt;Este artículo cubre cómo funciona el GC internamente, cómo medirlo, y los patrones concretos para reducir la presión de allocations — basado en el &lt;a href="https://dave.cheney.net/high-performance-go-workshop/dotgo-paris.html#memory-and-gc" rel="noopener noreferrer"&gt;High Performance Go Workshop de Dave Cheney&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Cómo piensa el GC de Go
&lt;/h2&gt;

&lt;p&gt;El garbage collector de Go solo actúa sobre el &lt;strong&gt;heap&lt;/strong&gt; — la memoria compartida donde viven los objetos que necesitan sobrevivir más allá del stack de la función que los creó. El stack de cada goroutine se gestiona solo: cuando una función retorna, su frame desaparece sin que el GC intervenga. La asignación en stack es esencialmente gratis.&lt;/p&gt;

&lt;p&gt;Al iniciar cada ciclo, el GC escanea todos los stacks activos buscando punteros que apuntan al heap. Esos son sus raíces — el punto de partida para construir el grafo de objetos vivos.&lt;/p&gt;

&lt;p&gt;El algoritmo es &lt;strong&gt;concurrent mark-sweep&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mark&lt;/strong&gt;: recorre el grafo desde las raíces y marca todo objeto alcanzable, &lt;em&gt;mientras tu programa sigue corriendo&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sweep&lt;/strong&gt;: libera la memoria de los objetos no marcados.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Imaginate un equipo de limpieza que entra a la oficina mientras vos seguís trabajando: primero anotan qué escritorios están ocupados, después retiran los vacíos. Para no descartar algo que se movió durante la limpieza, el runtime usa &lt;strong&gt;write barriers&lt;/strong&gt; — interceptores que registran cada escritura de puntero en tu programa. Esto mantiene la consistencia, pero tiene un costo: los write barriers se activan en &lt;em&gt;toda&lt;/em&gt; escritura de puntero, no solo durante el GC. Menos objetos en el heap significa menos punteros, menos write barriers, y menos overhead acumulado.&lt;/p&gt;

&lt;p&gt;La decisión de diseño central de Go es priorizar &lt;strong&gt;pause times bajos&lt;/strong&gt; sobre frecuencia de colección. El GC puede correr muchas veces si hay muchas allocations — eso es aceptable. Las pausas largas que congelen tu programa, no.&lt;/p&gt;




&lt;h2&gt;
  
  
  Cómo monitorear el GC
&lt;/h2&gt;

&lt;p&gt;Optimizar sin medir es adivinar. Go te da tres herramientas complementarias para entender qué está haciendo el GC antes de tocar una sola línea de código.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;GODEBUG=gctrace=1&lt;/code&gt;&lt;/strong&gt; es la más directa:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;GODEBUG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;gctrace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 ./mi-programa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cada ciclo de GC imprime una línea en stderr:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gc 1 @0.012s 2%: 0.015+1.2+0.050 ms clock, 4-&amp;gt;4-&amp;gt;2 MB, 5 MB goal, 8 P
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El fragmento &lt;code&gt;4-&amp;gt;4-&amp;gt;2 MB&lt;/code&gt; es el más informativo: heap antes de la colección, heap alcanzable durante el mark, heap después del sweep. Si el número del medio siempre se mantiene cercano al primero, tenés muchos objetos vivos que el GC no puede liberar — el problema está en tu estructura de datos, no en la frecuencia de allocations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Memory profiling con &lt;code&gt;pprof&lt;/code&gt;&lt;/strong&gt; te dice exactamente qué código está allocando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go tool pprof &lt;span class="nt"&gt;-alloc_objects&lt;/span&gt; mem.prof
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La métrica clave es &lt;code&gt;alloc_objects&lt;/code&gt; — la cantidad total de objetos creados — más que &lt;code&gt;inuse_bytes&lt;/code&gt;. Un objeto que nace y muere rápido no aparece en la memoria en uso, pero presiona el GC cada vez que se crea.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;El execution tracer&lt;/strong&gt; muestra las pausas del GC en una línea de tiempo real:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;-trace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;trace.out ./...
go tool trace trace.out
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esto abre una vista en el browser donde podés ver exactamente cuándo el GC interrumpió tu programa y cuánto duró cada pausa.&lt;/p&gt;

&lt;p&gt;Las tres herramientas se complementan: &lt;code&gt;gctrace&lt;/code&gt; dice &lt;em&gt;cuánto&lt;/em&gt; trabaja el GC, &lt;code&gt;pprof&lt;/code&gt; dice &lt;em&gt;quién&lt;/em&gt; le da trabajo, el tracer dice &lt;em&gt;cuándo&lt;/em&gt; interrumpe tu programa. La mayoría de los problemas de performance en Go no son algoritmos lentos — son allocation rates altos que fuerzan GC frecuente. Sin estos números, nunca sabés si tu optimización movió la aguja.&lt;/p&gt;




&lt;h2&gt;
  
  
  El costo oculto de strings y []byte
&lt;/h2&gt;

&lt;p&gt;El lugar donde más allocations accidentales ocurren en Go es en la interacción entre &lt;code&gt;string&lt;/code&gt; y &lt;code&gt;[]byte&lt;/code&gt;. Representan lo mismo — una secuencia de bytes — pero con contratos distintos: &lt;code&gt;string&lt;/code&gt; es inmutable, &lt;code&gt;[]byte&lt;/code&gt; es mutable. Cada conversión entre uno y otro copia los datos subyacentes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"hola mundo"&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c"&gt;// copia — nueva allocation&lt;/span&gt;
&lt;span class="n"&gt;s2&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;// copia otra vez — otra allocation&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En un hot path esto se acumula rápido. La regla práctica es simple: elegí una forma según dónde más se usa el dato y quedate en esa forma el mayor tiempo posible. Convertí solo en el borde.&lt;/p&gt;

&lt;p&gt;La &lt;strong&gt;concatenación con &lt;code&gt;+&lt;/code&gt;&lt;/strong&gt; tiene el mismo problema:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"hola"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"mundo"&lt;/span&gt; &lt;span class="c"&gt;// dos allocations intermedias&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cada &lt;code&gt;+&lt;/code&gt; crea un string nuevo. La solución es &lt;code&gt;strings.Builder&lt;/code&gt;, que acumula internamente un &lt;code&gt;[]byte&lt;/code&gt; y crea el string final solo cuando lo pedís:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Builder&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Grow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// opcional: reservar capacidad si conocés el tamaño aproximado&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hola"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mundo"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c"&gt;// única allocation&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hay una excepción interesante: cuando usás &lt;code&gt;[]byte&lt;/code&gt; como clave en un map, el compilador evita la allocation en conversiones inline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"algo"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="c"&gt;// el compilador optimiza esto — no siempre alloca&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esta optimización solo se aplica en el contexto de lookup directo en map. En cualquier otro contexto, la conversión tiene su costo.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;string&lt;/code&gt; y &lt;code&gt;[]byte&lt;/code&gt; son dos idiomas que dicen lo mismo. Cada traducción tiene un costo — hablá en un solo idioma el mayor tiempo posible.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Reutilizar memoria: pre-allocación y sync.Pool
&lt;/h2&gt;

&lt;p&gt;Si la estrategia anterior es &lt;em&gt;evitar&lt;/em&gt; allocations, esta es &lt;em&gt;reutilizar&lt;/em&gt; memoria que ya tenés.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pre-allocar slices cuando conocés el tamaño&lt;/strong&gt; elimina las re-allocations internas de &lt;code&gt;append&lt;/code&gt;. Cuando un slice se llena, Go duplica su capacidad y copia todo — eso puede pasar varias veces durante un loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Ineficiente: múltiples re-allocations durante el loop&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Eficiente: una sola allocation&lt;/span&gt;
&lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pre-allocar también mejora la &lt;strong&gt;cache locality&lt;/strong&gt;: todos los elementos quedan contiguos en memoria desde el principio. No necesitás saber el tamaño exacto — una buena estimación ya elimina la mayoría de las re-allocations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;sync.Pool&lt;/code&gt;&lt;/strong&gt; es el patrón para objetos que se crean y descartan frecuentemente, como buffers. En lugar de crear uno nuevo cada vez, lo tomás del pool, lo usás, y lo devolvés:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;bufPool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pool&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;bufPool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reset&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c"&gt;// siempre resetear antes de usar&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;bufPool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;// usás buf normalmente...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tres reglas que no podés olvidar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Siempre &lt;code&gt;Reset()&lt;/code&gt; antes de usar&lt;/strong&gt; — el objeto puede tener estado del uso anterior.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;El GC puede vaciar el pool&lt;/strong&gt; — &lt;code&gt;sync.Pool&lt;/code&gt; no es una caché persistente. No lo uses para guardar estado entre requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solo vale cuando hay overhead de creación real&lt;/strong&gt; — si el objeto es barato de crear, el pool agrega complejidad sin beneficio. Medí primero.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;La librería estándar usa &lt;code&gt;sync.Pool&lt;/code&gt; internamente en &lt;code&gt;fmt&lt;/code&gt;, &lt;code&gt;encoding/json&lt;/code&gt;, y otros paquetes de alto throughput. En servicios con alto volumen de requests, este patrón para buffers puede reducir las allocations por request a casi cero.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;El GC de Go solo gestiona el heap — el stack se limpia solo cuando retorna la función.&lt;/li&gt;
&lt;li&gt;El algoritmo es concurrent mark-sweep; prioriza pausas cortas sobre frecuencia de colección.&lt;/li&gt;
&lt;li&gt;Los write barriers añaden overhead a toda escritura de puntero — menos heap significa menos write barriers.&lt;/li&gt;
&lt;li&gt;Medí antes de optimizar: &lt;code&gt;gctrace&lt;/code&gt; para frecuencia, &lt;code&gt;pprof&lt;/code&gt; para fuentes, tracer para pausas.&lt;/li&gt;
&lt;li&gt;Las conversiones entre &lt;code&gt;string&lt;/code&gt; y &lt;code&gt;[]byte&lt;/code&gt; siempre copian — minimizá los cruces en el hot path.&lt;/li&gt;
&lt;li&gt;Usá &lt;code&gt;strings.Builder&lt;/code&gt; en lugar de concatenación con &lt;code&gt;+&lt;/code&gt; cuando armás strings dinámicamente.&lt;/li&gt;
&lt;li&gt;Pre-allocá slices con &lt;code&gt;make([]T, 0, n)&lt;/code&gt; cuando conocés el tamaño aproximado.&lt;/li&gt;
&lt;li&gt;Usá &lt;code&gt;sync.Pool&lt;/code&gt; para objetos costosos de crear que se reutilizan frecuentemente — y siempre &lt;code&gt;Reset()&lt;/code&gt; antes de usar.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dave.cheney.net/high-performance-go-workshop/dotgo-paris.html#memory-and-gc" rel="noopener noreferrer"&gt;High Performance Go Workshop — Dave Cheney&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://go.dev/blog/go15gc" rel="noopener noreferrer"&gt;Go GC: Prioritizing low latency and simplicity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pkg.go.dev/sync#Pool" rel="noopener noreferrer"&gt;&lt;code&gt;sync.Pool&lt;/code&gt; documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pkg.go.dev/strings#Builder" rel="noopener noreferrer"&gt;&lt;code&gt;strings.Builder&lt;/code&gt; documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;¿Te resultó útil? Seguime en dev.to para más artículos sobre performance en Go y sistemas de alto throughput. Los comentarios y preguntas son bienvenidos — respondé abajo.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>performance</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
