Analyzing and improving memory usage in Go

Scott Gangemi
10 min readbeginner
--
View Original

Overview

This article focuses on optimizing memory usage in Go applications, specifically through the analysis of a real-world application at SafetyCulture. It discusses the use of pprof for profiling memory allocation and details experiments conducted to reduce memory usage and improve performance.

What You'll Learn

1

How to use pprof for memory profiling in Go applications

2

Why reducing unnecessary data fields can optimize memory usage

3

How to implement streaming JSON decoding to minimize memory footprint

Prerequisites & Requirements

  • Basic understanding of Go programming and memory management concepts
  • Familiarity with pprof for profiling Go applications(optional)

Key Questions Answered

How can I analyze memory usage in my Go application?
You can analyze memory usage in your Go application by using the pprof tool, which allows you to visualize profiling data collected from a running application. This tool helps identify memory allocation hotspots, making it easier to target optimizations.
What impact does removing unused fields from JSON requests have on memory usage?
Removing unused fields from JSON requests can significantly reduce memory allocation. In the article, it was shown that after removing an unnecessary field, memory usage dropped from an average of 100MB-250MB to 70MB-90MB, demonstrating a clear benefit in performance.
What are the benefits of streaming JSON decoding in Go?
Streaming JSON decoding allows for processing large JSON objects without loading the entire object into memory at once. This method can lead to reduced memory usage and improved performance, especially when dealing with large responses that can exceed 20MB.
How did the changes affect the 99th percentile latency of the application?
The changes implemented in the application reduced the 99th percentile latency from around 1.2 seconds to approximately 500 milliseconds. This improvement enhances the user experience by providing faster response times under load.

Key Statistics & Figures

Average memory usage before optimization
100MB-250MB
This was the memory usage range before any changes were made.
Average memory usage after optimization
70MB-90MB
Post-optimization, the average memory usage dropped significantly.
Max GC pause time before optimization
400ms
The maximum GC pause time was around 400ms before any improvements were implemented.
Max GC pause time after optimization
300ms
After optimizations, the max GC pause time improved to around 300ms, with many pauses now around 100ms.
99th percentile latency before optimization
1.2 seconds
This was the latency experienced by users before any performance improvements.
99th percentile latency after optimization
500ms
The latency was reduced to approximately 500ms after the changes were deployed.

Technologies & Tools

Some links below are affiliate links. We may earn a commission if you make a purchase.

Backend
Go
The programming language used for developing the application and implementing memory optimizations.
Tool
Pprof
A built-in Go tool used for profiling and visualizing memory usage.
Data Format
JSON
The format used for data exchange in API requests and responses.

Key Actionable Insights

1
Utilize pprof in production to gather realistic profiling data for memory usage analysis.
Running pprof in a production environment gives you a clear picture of how your application behaves under real user load, allowing for more accurate optimizations.
2
Consider removing unused fields from API requests to optimize memory allocation.
In the article, removing an unnecessary field led to significant reductions in memory usage, showcasing the importance of reviewing and cleaning up API responses.
3
Implement streaming JSON decoding for large payloads to minimize memory footprint.
By using streaming decoding, you can process large JSON objects without overwhelming memory, which is crucial for applications that handle substantial data volumes.

Common Pitfalls

1
Failing to profile applications in production can lead to misleading optimization efforts.
Profiling in a non-production environment may not accurately reflect real-world usage, which can result in ineffective optimizations.
2
Neglecting to review API response fields can lead to unnecessary memory usage.
If developers do not regularly audit the fields included in API responses, they may continue to allocate memory for data that is no longer needed.

Related Concepts

Memory Management In Go
Performance Optimization Techniques
Profiling Tools For Go Applications