Case 7: The Memory Eater - Building Strings in Loops
The Story
Imagine you are building a feature to export a list of products into a CSV file. This file is just a long piece of text. You have a list of thousands of products.
The easiest way to create this text is to loop through all the products and add each product's information to the text, one by one.
The Problem Code (It Looks So Simple!)
Here is a common way a developer might write the code:
public string GenerateCsvReport(List<Product> products)
{
// Start with the header line
string csvContent = "Id,Name,Price\n";
// Mistake: Using '+' to add text in a big loop
foreach (var product in products)
{
csvContent += $"{product.Id},{product.Name},{product.Price}\n";
}
return csvContent;
}This code looks clean and easy to understand. But it hides a big problem.
Why is this a problem?
Strings Cannot Be Changed: In C#, once you create a string, you can never change it. It's "immutable."
What Happens When You Use
+=?When the code runs
csvContent += ..., it doesn't just add new text to the old string. Instead, in every single loop, it does this:- Creates a brand new, bigger string in memory.
- Copies everything from the old string into the new one.
- Adds the new product's text at the end.
- The old string is now useless garbage.
The Bad Results:
- Huge Memory Use: If you have 10,000 products, this code creates 10,001 separate strings in memory. Each one is bigger than the last.
- Slow Performance: The computer's Garbage Collector (GC) has to work very hard to clean up all the old, useless strings. This uses a lot of CPU power and can make your app pause or freeze.
The Solution: Use StringBuilder
The StringBuilder class is made for this exact situation. It creates a special container (a buffer) for your text. It only asks for more memory when the container is full, not every time you add text.
Here is the better code:
public string GenerateCsvReport(List<Product> products)
{
// Give StringBuilder an idea of how much space it will need. This is even faster.
var csvBuilder = new StringBuilder(products.Count * 50);
csvBuilder.AppendLine("Id,Name,Price");
foreach (var product in products)
{
// Use .Append() to add text without creating new strings
csvBuilder.Append(product.Id)
.Append(',')
.Append(product.Name)
.Append(',')
.AppendLine(product.Price.ToString());
}
// Create the final string only once, at the very end.
return csvBuilder.ToString();
}What We Gained
- Less Memory: Instead of 10,001 strings, we only create one
StringBuilderand one final string. - Happy Garbage Collector: The GC has almost no garbage to clean up, so the app runs smoothly.
- Much Faster: The code is much faster because it's not copying text over and over again.
The Golden Rule
Never use the + or += operator to join strings inside a loop.
Always use StringBuilder when you need to build a string piece by piece, especially in a loop. It's a simple change that makes a huge difference.