<?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>Forem: Tyler Bui-Palsulich</title>
    <description>The latest articles on Forem by Tyler Bui-Palsulich (@tbpalsulich).</description>
    <link>https://forem.com/tbpalsulich</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F450198%2F24317b2a-a706-45b2-9b22-0456035018da.jpg</url>
      <title>Forem: Tyler Bui-Palsulich</title>
      <link>https://forem.com/tbpalsulich</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/tbpalsulich"/>
    <language>en</language>
    <item>
      <title>Finding and fixing memory leaks in Go</title>
      <dc:creator>Tyler Bui-Palsulich</dc:creator>
      <pubDate>Wed, 11 Aug 2021 15:05:22 +0000</pubDate>
      <link>https://forem.com/googlecloud/finding-and-fixing-memory-leaks-in-go-1k1h</link>
      <guid>https://forem.com/googlecloud/finding-and-fixing-memory-leaks-in-go-1k1h</guid>
      <description>&lt;p&gt;This post reviews how I found a memory leak, how I fixed it, how I fixed similar issues in Google's sample Go code, and how we're improving our libraries to prevent this in the future.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/googleapis/google-cloud-go" rel="noopener noreferrer"&gt;Google Cloud Client Libraries for Go&lt;/a&gt; generally use gRPC under the hood to connect with Google Cloud APIs. When you create an API client, the library initializes a connection to the API then leaves that connection open until you call &lt;code&gt;Close&lt;/code&gt; on the &lt;code&gt;Client&lt;/code&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;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c"&gt;// Check err.&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Clients are safe to use concurrently, so you should keep the same &lt;code&gt;Client&lt;/code&gt; around until you're done with it. But, what happens if you don't &lt;code&gt;Close&lt;/code&gt; the client when you should?&lt;/p&gt;

&lt;p&gt;You get a memory leak. The underlying connections never get cleaned up.&lt;/p&gt;




&lt;p&gt;Google has a bunch of GitHub automation bots to help manage hundreds of GitHub repos. Some of our bots proxy their requests through a &lt;a href="https://github.com/googleapis/repo-automation-bots/tree/main/serverless-scheduler-proxy" rel="noopener noreferrer"&gt;Go server&lt;/a&gt; running on &lt;a href="https://cloud.google.com/run/docs/quickstarts/build-and-deploy/go" rel="noopener noreferrer"&gt;Cloud Run&lt;/a&gt;. Our memory usage looked like a classic sawtooth memory leak:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1dmpo6x8cky6t9dsqsex.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1dmpo6x8cky6t9dsqsex.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I started debugging by adding the &lt;code&gt;pprof.Index&lt;/code&gt; handler to the server:&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;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/debug/pprof/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pprof&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://pkg.go.dev/net/http/pprof" rel="noopener noreferrer"&gt;&lt;code&gt;pprof&lt;/code&gt;&lt;/a&gt; provides runtime profiling data, like memory usage. See &lt;a href="https://blog.golang.org/pprof" rel="noopener noreferrer"&gt;Profiling Go Programs&lt;/a&gt; on the Go Blog for more information.&lt;/p&gt;

&lt;p&gt;Then, I built and started the server locally:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ go build
$ PROJECT_ID=my-project PORT=8080 ./serverless-scheduler-proxy


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Next, I sent a some requests requests to the server:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

for i in {1..5}; do
curl --header "Content-Type: application/json" --request POST --data '{"name": "HelloHTTP", "type": "testing", "location": "us-central1"}' localhost:8080/v0/cron
echo " -- $i"
done


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The exact payload and endpoint is specific to our server and is irrelevant for this post.&lt;/p&gt;

&lt;p&gt;To get a baseline for what memory is being used, I collected some initial &lt;code&gt;pprof&lt;/code&gt; data:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

curl http://localhost:8080/debug/pprof/heap &amp;gt; heap.0.pprof


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Inspecting the output, you can see some memory usage, but nothing immediately stands out as a large issue (which is good! We just started the server!):&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ go tool pprof heap.0.pprof
File: serverless-scheduler-proxy
Type: inuse_space
Time: May 4, 2021 at 9:33am (EDT)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) top10
Showing nodes accounting for 2129.67kB, 100% of 2129.67kB total
Showing top 10 nodes out of 30
      flat  flat%   sum%        cum   cum%
 1089.33kB 51.15% 51.15%  1089.33kB 51.15%  google.golang.org/grpc/internal/transport.newBufWriter (inline)
  528.17kB 24.80% 75.95%   528.17kB 24.80%  bufio.NewReaderSize (inline)
  512.17kB 24.05%   100%   512.17kB 24.05%  google.golang.org/grpc/metadata.Join
         0     0%   100%   512.17kB 24.05%  cloud.google.com/go/secretmanager/apiv1.(*Client).AccessSecretVersion
         0     0%   100%   512.17kB 24.05%  cloud.google.com/go/secretmanager/apiv1.(*Client).AccessSecretVersion.func1
         0     0%   100%   512.17kB 24.05%  github.com/googleapis/gax-go/v2.Invoke
         0     0%   100%   512.17kB 24.05%  github.com/googleapis/gax-go/v2.invoke
         0     0%   100%   512.17kB 24.05%  google.golang.org/genproto/googleapis/cloud/secretmanager/v1.(*secretManagerServiceClient).AccessSecretVersion
         0     0%   100%   512.17kB 24.05%  google.golang.org/grpc.(*ClientConn).Invoke
         0     0%   100%  1617.50kB 75.95%  google.golang.org/grpc.(*addrConn).createTransport


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The next step was sending a bunch of requests to the server and seeing if we could (1) reproduce the seeming memory leak and (2) identify what the leak is.&lt;/p&gt;

&lt;p&gt;Sending 500 requests:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

for i in {1..500}; do
curl --header "Content-Type: application/json" --request POST --data '{"name": "HelloHTTP", "type": "testing", "location": "us-central1"}' localhost:8080/v0/cron
echo " -- $i"
done


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Collecting and analyzing more &lt;code&gt;pprof&lt;/code&gt; data:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ curl http://localhost:8080/debug/pprof/heap &amp;gt; heap.6.pprof
$ go tool pprof heap.6.pprof
File: serverless-scheduler-proxy
Type: inuse_space
Time: May 4, 2021 at 9:50am (EDT)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) top10
Showing nodes accounting for 94.74MB, 94.49% of 100.26MB total
Dropped 26 nodes (cum &amp;lt;= 0.50MB)
Showing top 10 nodes out of 101
      flat  flat%   sum%        cum   cum%
   51.59MB 51.46% 51.46%    51.59MB 51.46%  google.golang.org/grpc/internal/transport.newBufWriter
   19.60MB 19.55% 71.01%    19.60MB 19.55%  bufio.NewReaderSize
    6.02MB  6.01% 77.02%     6.02MB  6.01%  bytes.makeSlice
    4.51MB  4.50% 81.52%    10.53MB 10.51%  crypto/tls.(*Conn).readHandshake
       4MB  3.99% 85.51%     4.50MB  4.49%  crypto/x509.parseCertificate
       3MB  2.99% 88.51%        3MB  2.99%  crypto/tls.Client
    2.50MB  2.49% 91.00%     2.50MB  2.49%  golang.org/x/net/http2/hpack.(*headerFieldTable).addEntry
    1.50MB  1.50% 92.50%     1.50MB  1.50%  google.golang.org/grpc/internal/grpcsync.NewEvent
       1MB     1% 93.50%        1MB     1%  runtime.malg
       1MB     1% 94.49%        1MB     1%  encoding/json.(*decodeState).literalStore


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;google.golang.org/grpc/internal/transport.newBufWriter&lt;/code&gt; really stands out as using a ton of memory! That's the first indication of what the leak is related to: gRPC. Looking at our application source code, the only place we were using gRPC was for &lt;a href="https://cloud.google.com/secret-manager/docs/quickstart" rel="noopener noreferrer"&gt;Google Cloud Secret Manager&lt;/a&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;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;secretmanager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to create secretmanager client: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&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;We never called &lt;code&gt;client.Close()&lt;/code&gt; and created a &lt;code&gt;Client&lt;/code&gt; on every request! So, I added a &lt;code&gt;Close&lt;/code&gt; call and the problem went away:&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;defer&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I submitted the fix, it &lt;a href="https://cloud.google.com/build/docs/deploying-builds/deploy-cloud-run" rel="noopener noreferrer"&gt;automatically deployed&lt;/a&gt;, and the sawtooth went away immediately!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz46xksxzus3aluo3cu4k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz46xksxzus3aluo3cu4k.png" alt="" start=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Woohoo! 🎉🎉🎉&lt;/p&gt;




&lt;p&gt;Around the same time, a user filed an issue on our &lt;a href="https://github.com/GoogleCloudPlatform/golang-samples" rel="noopener noreferrer"&gt;Go sample repo for Cloud&lt;/a&gt;, which contains most of the Go samples for docs on &lt;a href="https://cloud.google.com" rel="noopener noreferrer"&gt;cloud.google.com&lt;/a&gt;. The user noticed we forgot to &lt;code&gt;Close&lt;/code&gt; the &lt;code&gt;Client&lt;/code&gt; in one of our samples!&lt;/p&gt;

&lt;p&gt;I had seen the same thing pop up a few other times, so I decided to investigate the entire repo.&lt;/p&gt;

&lt;p&gt;I started with a rough estimate of how many affected files there were. Using &lt;code&gt;grep&lt;/code&gt;, we can get a list of all files containing a &lt;code&gt;NewClient&lt;/code&gt; style call, then pass that list to another invocation of &lt;code&gt;grep&lt;/code&gt; to only list the files that &lt;em&gt;don't&lt;/em&gt; contain &lt;code&gt;Close&lt;/code&gt;, ignoring test files:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ grep -L Close $(grep -El 'New[^(]*Client' **/*.go) | grep -v test


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Oops! There were 207 files… For context, we have about 1300 &lt;code&gt;.go&lt;/code&gt; files in the &lt;a href="https://github.com/GoogleCloudPlatform/golang-samples" rel="noopener noreferrer"&gt;GoogleCloudPlatform/golang-samples&lt;/a&gt; repo.&lt;/p&gt;

&lt;p&gt;Given the scale of the problem, I thought some automation would be &lt;a href="https://xkcd.com/1205/" rel="noopener noreferrer"&gt;worth it&lt;/a&gt; to get a rough start. I didn't want to write a full on Go program to edit the files, so I stuck with Bash:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ grep -L Close $(grep -El 'New[^(]*Client' **/*.go) | grep -v test | xargs sed -i '/New[^(]*Client/,/}/s/}/}\ndefer client.Close()/'


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Is it perfect? No. Did it make a huge dent in the amount of work? Yes!&lt;/p&gt;

&lt;p&gt;The first part (up until &lt;code&gt;test&lt;/code&gt;) is the exact same as above -- get a list of all of the possibly affected files (the ones that seem to create a &lt;code&gt;Client&lt;/code&gt; but never call &lt;code&gt;Close&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Then, I passed that list of files to &lt;code&gt;sed&lt;/code&gt; for actual editing. &lt;code&gt;xargs&lt;/code&gt; invokes the command you give it with each line of &lt;code&gt;stdin&lt;/code&gt; being passed as an argument to the given command.&lt;/p&gt;

&lt;p&gt;To understand the &lt;code&gt;sed&lt;/code&gt; command, it helps to see what a sample usually looks like in the &lt;code&gt;golang-samples&lt;/code&gt; repo (omitting imports and everything after client initialization):&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;// accessSecretVersion accesses the payload for the given secret version if one&lt;/span&gt;
&lt;span class="c"&gt;// exists. The version can be a version number as a string (e.g. "5") or an&lt;/span&gt;
&lt;span class="c"&gt;// alias (e.g. "latest").&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;accessSecretVersion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Writer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&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;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// name := "projects/my-project/secrets/my-secret/versions/5"&lt;/span&gt;
    &lt;span class="c"&gt;// name := "projects/my-project/secrets/my-secret/versions/latest"&lt;/span&gt;
    &lt;span class="c"&gt;// Create the client.&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;secretmanager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to create secretmanager client: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;At a high level, we initialize the client and check if there was an error. Whenever you check the error, there is a closing curly brace (&lt;code&gt;}&lt;/code&gt;). I used that information to automate the editing.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;sed&lt;/code&gt; command is still a douzy, though:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

sed -i '/New[^(]*Client/,/}/s/}/}\ndefer client.Close()/'


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;-i&lt;/code&gt; says to edit the files in place. I'm OK with this because &lt;code&gt;git&lt;/code&gt; can save me if I mess up.&lt;/p&gt;

&lt;p&gt;Next, I used the &lt;code&gt;s&lt;/code&gt; command to insert &lt;code&gt;defer client.Close()&lt;/code&gt; right after the presumed closing curly brace (&lt;code&gt;}&lt;/code&gt;) from checking the error.&lt;/p&gt;

&lt;p&gt;But, I don't want to replace &lt;em&gt;every&lt;/em&gt; &lt;code&gt;}&lt;/code&gt;, I only want the &lt;em&gt;first one after a call to &lt;code&gt;NewClient&lt;/code&gt;&lt;/em&gt;. To do that, you can give an &lt;a href="https://www.gnu.org/software/sed/manual/html_node/Addresses.html" rel="noopener noreferrer"&gt;&lt;em&gt;address range&lt;/em&gt;&lt;/a&gt; for &lt;code&gt;sed&lt;/code&gt; to search.&lt;/p&gt;

&lt;p&gt;An address range can include the start and end patterns to match before applying whatever command comes next. In this case, the start is &lt;code&gt;/New[^(]*Client/&lt;/code&gt;, matching &lt;code&gt;NewClient&lt;/code&gt; type calls, and the end (separated by a &lt;code&gt;,&lt;/code&gt;) is &lt;code&gt;/}/&lt;/code&gt;, matching the next curly brace. That means our search and replace will only apply between the call to &lt;code&gt;NewClient&lt;/code&gt; and the closing curly brace! &lt;/p&gt;

&lt;p&gt;From knowing the error handling pattern above, the closing brace of the &lt;code&gt;if err != nil&lt;/code&gt; condition is exactly where we want to insert our &lt;code&gt;Close&lt;/code&gt; call.&lt;/p&gt;




&lt;p&gt;Once I had automatically edited all of the samples, I ran &lt;code&gt;goimports&lt;/code&gt; to fix the formatting. Then, I went through each edited file to make sure it did the right thing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In server applications, should we actually close the client, or should we keep it around for future requests?&lt;/li&gt;
&lt;li&gt;Is the name of the &lt;code&gt;Client&lt;/code&gt; actually &lt;code&gt;client&lt;/code&gt; or is it something else?&lt;/li&gt;
&lt;li&gt;Is there more than one &lt;code&gt;Client&lt;/code&gt; to &lt;code&gt;Close&lt;/code&gt;?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once that was done, I was left with &lt;a href="https://github.com/GoogleCloudPlatform/golang-samples/pull/2080" rel="noopener noreferrer"&gt;180 files edited&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;The last order of business is trying to make it so this doesn't happen to users anymore. There are a few ways we have in mind:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Better samples. See above.&lt;/li&gt;
&lt;li&gt;Better GoDoc. We updated our library generator to include a comment in the generated libraries saying to &lt;code&gt;Close&lt;/code&gt; the &lt;code&gt;Client&lt;/code&gt; when you're done with it. See &lt;a href="https://github.com/googleapis/google-cloud-go/issues/3031" rel="noopener noreferrer"&gt;https://github.com/googleapis/google-cloud-go/issues/3031&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Better libraries. Is there a way we can automatically &lt;code&gt;Close&lt;/code&gt; clients? Finalizers? Have an idea of how we can do this better? Let us know on &lt;a href="https://github.com/googleapis/google-cloud-go/issues/4498" rel="noopener noreferrer"&gt;https://github.com/googleapis/google-cloud-go/issues/4498&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I hope you learned a bit about Go, memory leaks, &lt;code&gt;pprof&lt;/code&gt;, gRPC, and Bash. I'd love to hear your stories about memory leaks you've found and what it took to fix them! If you have ideas about how we can improve our &lt;a href="https://github.com/googleapis/google-cloud-go" rel="noopener noreferrer"&gt;libraries&lt;/a&gt; or &lt;a href="https://github.com/GoogleCloudPlatform/golang-samples" rel="noopener noreferrer"&gt;samples&lt;/a&gt;, let us know by filing an issue.&lt;/p&gt;

</description>
      <category>go</category>
      <category>pprof</category>
    </item>
    <item>
      <title>Why Go modules are faster than GOPATH</title>
      <dc:creator>Tyler Bui-Palsulich</dc:creator>
      <pubDate>Mon, 10 Aug 2020 15:16:43 +0000</pubDate>
      <link>https://forem.com/tbpalsulich/why-go-modules-are-faster-than-gopath-blj</link>
      <guid>https://forem.com/tbpalsulich/why-go-modules-are-faster-than-gopath-blj</guid>
      <description>&lt;p&gt;Downloading dependencies with Go modules can be significantly faster than using &lt;code&gt;GOPATH&lt;/code&gt;-based dependency management. A fresh dependency download experiment for this post took 9 minutes and 33.845 seconds in GOPATH mode and 10.185 seconds in module mode. This post explains why. The key difference is that modules avoid deep repository clones and can use a module proxy.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For an introduction to Go modules, see &lt;a href="https://blog.golang.org/using-go-modules"&gt;https://blog.golang.org/using-go-modules&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;GOPATH&lt;/code&gt;-based dependency management downloads every dependency into &lt;code&gt;GOPATH/src&lt;/code&gt;, doing a deep clone of the version control repository in the process.&lt;/p&gt;

&lt;p&gt;So, if you're in &lt;code&gt;GOPATH&lt;/code&gt; mode and your project depends on A, which depends on B, which depends on C, the &lt;code&gt;go&lt;/code&gt; command will &lt;code&gt;git clone&lt;/code&gt; all three repositories (assuming they're all using git).&lt;/p&gt;

&lt;p&gt;When using Go modules, you need two things when downloading a dependency:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The dependency's source code.&lt;/li&gt;
&lt;li&gt;The dependency's &lt;code&gt;go.mod&lt;/code&gt; file.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;code&gt;go.mod&lt;/code&gt; file is used to figure out which version of every dependency you need. Once the &lt;code&gt;go&lt;/code&gt; command collects all of the &lt;code&gt;go.mod&lt;/code&gt; files from all of your dependencies, it can figure out which version of each dependency you need for &lt;em&gt;your&lt;/em&gt; project.&lt;/p&gt;

&lt;p&gt;For example, if you depend on modules A and B directly, and module A depends on v1.2.0 of module B, your module needs to depend on &lt;em&gt;at a minimum&lt;/em&gt; B v1.2.0. This same idea is applied to every module you depend on, either directly or indirectly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kqVK1LMr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1clhk3x0t5nnq7669w7k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kqVK1LMr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1clhk3x0t5nnq7669w7k.png" alt="Dependency graph showing how A's dependency on B v1.2.0 means your project must depend on at least B v1.2.0."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Side note: notice that if a new version of module A or B is released, that doesn't change the &lt;em&gt;minimum&lt;/em&gt; version of B you must depend on. That requirement is stable over time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Module proxy
&lt;/h2&gt;

&lt;p&gt;Module proxies are a huge reason why Go modules are so much faster. A module proxy understands the two components you need from every module dependency: the source code and the &lt;code&gt;go.mod&lt;/code&gt; file. That understanding leads to two separate optimizations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Source code can be distributed as a zip file instead of a deep VCS clone. Downloading a single zip file is much faster than doing a full VCS clone, making module downloads more efficient than GOPATH.&lt;/li&gt;
&lt;li&gt;You can download a &lt;code&gt;go.mod&lt;/code&gt; file without getting the rest of the source code. This makes using a module proxy more efficient than not using a proxy.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Optimization #1&lt;/strong&gt; means when the &lt;code&gt;go&lt;/code&gt; command downloads a dependency, there is less to download compared to &lt;code&gt;GOPATH&lt;/code&gt;. Instead of having to (usually) do a full &lt;code&gt;git clone&lt;/code&gt;, the &lt;code&gt;go&lt;/code&gt; command downloads a single zip file with the source code of the module version you're asking for.&lt;/p&gt;

&lt;p&gt;If you are using modules &lt;em&gt;without&lt;/em&gt; a proxy, the &lt;code&gt;go&lt;/code&gt; command does a shallow clone whenever possible. A shallow clone is much faster than a deep clone because you are only retrieving a single commit, rather than the full repository history.&lt;/p&gt;

&lt;p&gt;The result is that, when using modules, there is simply &lt;em&gt;less stuff&lt;/em&gt; to download compared to &lt;code&gt;GOPATH&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Optimization #2&lt;/strong&gt;, understanding &lt;code&gt;go.mod&lt;/code&gt; files, is more subtle.&lt;/p&gt;

&lt;p&gt;Just because a module is in your &lt;em&gt;module graph&lt;/em&gt; doesn't mean it's in your &lt;em&gt;import graph&lt;/em&gt;. The module graph includes the entire list of modules included in your &lt;code&gt;go.mod&lt;/code&gt; file, all your dependencies' &lt;code&gt;go.mod&lt;/code&gt; files, all of &lt;em&gt;their&lt;/em&gt; dependencies' &lt;code&gt;go.mod&lt;/code&gt; files, and so on. The import graph contains all of the &lt;em&gt;packages&lt;/em&gt; imported by your project, the packages that &lt;em&gt;those&lt;/em&gt; packages import, and so on. &lt;strong&gt;A module you depend on can contain packages you don't need to compile your project.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For example, let's say you depend on a database helper with support for Postgres, MySQL, and MongoDB. The helper has a separate package for each supported database and each one depends on a third-party module/package to communicate with that database. Your project only uses the helper's Postgres package, so you don't need the MySQL or MongoDB packages to build your project. Further, you don't need the source code for the MySQL or MongoDB modules to compile your project—they aren't in the import graph!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--70jnh4t8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/10g413on8oy5nrerl8fp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--70jnh4t8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/10g413on8oy5nrerl8fp.png" alt="Dependency graph for the database example showing the import graph as a subset of the module graph."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, you &lt;em&gt;do&lt;/em&gt; need the &lt;code&gt;go.mod&lt;/code&gt; file for those modules. If a module is in your module graph, it must be taken into account when figuring out the minimum version of each dependency to use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here is where a module proxy comes to the rescue.&lt;/strong&gt; A module proxy can give you &lt;em&gt;just&lt;/em&gt; the &lt;code&gt;go.mod&lt;/code&gt; file for any given module, without the source code. If you &lt;em&gt;aren't&lt;/em&gt; using a proxy, you need to clone the entire repo (source code and all) just to get the &lt;code&gt;go.mod&lt;/code&gt; file, &lt;em&gt;knowing&lt;/em&gt; that code will never be compiled. Notably, as mentioned above, the &lt;code&gt;go&lt;/code&gt; command in module mode does a shallow clone whenever possible.&lt;/p&gt;

&lt;p&gt;When you're in &lt;code&gt;GOPATH&lt;/code&gt; mode, the &lt;code&gt;go&lt;/code&gt; command only downloads the dependencies that are in your import graph. So, this particular proxy optimization only improves performance compared to not using a module proxy. &lt;a href="http://golang.org/issues/36460"&gt;Lazy module loading&lt;/a&gt; (planned for Go 1.16) will speed up modules even more by reducing the number of &lt;code&gt;go.mod&lt;/code&gt; files that the &lt;code&gt;go&lt;/code&gt; command needs to fetch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;p&gt;The optimizations above mean that (1) the stuff you download is smaller and (2) there are fewer things to download.&lt;/p&gt;

&lt;p&gt;Combined, a fresh module download can be around 5 times faster when using a proxy versus without. When compared to &lt;code&gt;GOPATH&lt;/code&gt;, using modules with a proxy can be over 50 times faster.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It's theoretically possible for modules to be slower because you need to download each version of a dependency separately, rather than only having a single version of the dependency in your system. In practice, modules are much faster and the cache requires less space on disk, especially when you factor in standard GOPATH+vendoring patterns.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Try it out
&lt;/h2&gt;

&lt;p&gt;To see these optimizations in action, try the following commands with a dependency of your choice. &lt;a href="https://golang.org/doc/go1.13"&gt;Starting with Go 1.13&lt;/a&gt;, the default module proxy is &lt;a href="http://proxy.golang.org"&gt;proxy.golang.org&lt;/a&gt;—if you're using Go 1.13 or later, using modules, and haven't adjusted &lt;code&gt;GOPROXY&lt;/code&gt;, you're already getting these benefits.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I used &lt;a href="https://cloud.google.com/shell"&gt;Cloud Shell&lt;/a&gt; to run these tests. Your results may vary depending on the machine you're using, the Go version you're using, your network speed, the dependency you test with, and other factors.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Start by creating a temporary, empty &lt;code&gt;GOPATH&lt;/code&gt; to test with to avoid deleting the normal &lt;code&gt;GOPATH&lt;/code&gt; contents.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mkdir /tmp/tmp.GOPATH
$ export GOPATH=/tmp/tmp.GOPATH
$ go env GOPATH # Just to confirm.
/tmp/tmp.GOPATH
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now, try downloading a dependency in &lt;code&gt;GOPATH&lt;/code&gt; mode. These commands use &lt;a href="http://pkg.go.dev/cloud.google.com/go/storage"&gt;cloud.google.com/go/storage&lt;/a&gt;, but you can try with whatever dependency you'd like:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Force GOPATH mode. Be sure the current directory
# doesn't have a go.mod.
$ export GO111MODULES=off
$ time go get cloud.google.com/go/storage
real    9m33.845s
user    4m1.197s
sys     0m18.079s
&lt;/code&gt;&lt;/pre&gt;


&lt;blockquote&gt;
&lt;p&gt;You can find the &lt;a href="http://pkg.go.dev/cloud.google.com/go/storage"&gt;cloud.google.com/go/storage&lt;/a&gt; &lt;code&gt;go.mod&lt;/code&gt; file &lt;a href="https://github.com/googleapis/google-cloud-go/blob/master/storage/go.mod"&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next, try using Go modules. Create a new module to test with:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mkdir proxy-testing
$ cd proxy-testing
$ unset GO111MODULES # Back to the default.
$ go mod init example.com/proxy-testing
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now, try downloading a dependency without a proxy:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ go clean -modcache # Careful!
$ go env -w GOPROXY=direct # direct means go directly to the source.
$ go env GOPROXY
direct
$ time go get cloud.google.com/go/storage
go: finding cloud.google.com/go/storage v1.10.0
...

real    2m6.396s
user    1m51.447s
sys     0m18.311s
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now try it with the proxy enabled (by resetting &lt;code&gt;GOPROXY&lt;/code&gt; to the default):&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ go env -w GOPROXY=
$ go env GOPROXY
https://proxy.golang.org,direct
$ go clean -modcache # Careful!
$ go mod tidy # To start from the same state as before.
$ time go get cloud.google.com/go/storage
go: finding cloud.google.com/go/storage v1.10.0
...

real    0m10.185s
user    0m9.610s
sys     0m1.961s
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ytbZGdq2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/0a9aq55v44da664wi8un.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ytbZGdq2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/0a9aq55v44da664wi8un.png" alt="Bar chart comparing the three experiments. Data summarized below."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Downloading &lt;a href="http://pkg.go.dev/cloud.google.com/go/storage"&gt;cloud.google.com/go/storage&lt;/a&gt; took:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;9m33.845s in &lt;code&gt;GOPATH&lt;/code&gt; mode,&lt;/li&gt;
&lt;li&gt;2m6.396s using modules &lt;em&gt;without&lt;/em&gt; a proxy, and&lt;/li&gt;
&lt;li&gt;10.185s using modules &lt;em&gt;with&lt;/em&gt; a proxy (the default).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you run these tests on your machine, the results will vary. However, modules are dramatically faster than &lt;code&gt;GOPATH&lt;/code&gt;, especially when using the default proxy.&lt;/p&gt;

</description>
      <category>go</category>
    </item>
  </channel>
</rss>
