<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/the-fasting-developer-memory-discipline-and-gc-awareness-in-net-5yq85h552" -->

---
title: The Fasting Developer: Memory Discipline and GC...
description: A deep dive into .NET memory discipline and GC-aware coding practices. Covers how the generational garbage collector works and why short-lived objects that...
canonical: https://daily.dev/posts/the-fasting-developer-memory-discipline-and-gc-awareness-in-net-5yq85h552
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: The Fasting Developer: Memory Discipline and GC Awareness in .NET | daily.dev
og:description: A deep dive into .NET memory discipline and GC-aware coding practices. Covers how the generational garbage collector works and why short-lived objects that...
og:url: https://daily.dev/posts/the-fasting-developer-memory-discipline-and-gc-awareness-in-net-5yq85h552
og:image: https://api.daily.dev/og/posts/5yQ85h552.png
og:image:alt: The Fasting Developer: Memory Discipline and GC Awareness in .NET
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# The Fasting Developer: Memory Discipline and GC Awareness in .NET

**[We Are .NET](https://daily.dev/sources/wearedotnet)** · 9 min read · 12 upvotes · 0 comments

## Summary

A deep dive into .NET memory discipline and GC-aware coding practices. Covers how the generational garbage collector works and why short-lived objects that survive collections cause latency spikes. Practical techniques include: using value types and readonly structs to avoid heap allocations, Span<T> and stackalloc for zero-allocation reads, string.Create for building strings without intermediates, SearchValues<T> for vectorized character search in .NET 8+, ArrayPool<T> for buffer reuse, and avoiding hidden allocations from closures and Task vs ValueTask. Includes profiling guidance using dotnet-trace and BenchmarkDotNet with [MemoryDiagnoser].

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://www.binaryintellect.net/articles/f3c06695-d347-4ede-89a8-6ff39c3e4049.aspx>

## Questions this post answers

### How much memory does string.Split allocate compared to using Span<char> for parsing a string?

Splitting a string with string.Split typically allocates 72 to 96 bytes per call, since it creates a string array plus multiple substrings. Parsing the same value with ReadOnlySpan<char> and AsSpan/LastIndexOf/TryParse results in zero allocations, because the span operates directly on the existing string's memory instead of copying it.

_Developers chasing GC-driven latency spikes compare allocation costs like these on daily.dev before optimizing hot paths._

### What does SearchValues<T> in .NET 8 do differently from IndexOfAny for searching characters?

SearchValues<T>, introduced in .NET 8, pre-computes a vectorized lookup table once and reuses it across all subsequent searches, whereas the standard IndexOfAny(char[]) rebuilds its lookup on every call. Declaring it as a static readonly field means the pre-computation happens once at startup, and searches then run using SIMD instructions where available, giving substantially higher throughput on large inputs.

_Teams tuning .NET hot paths track SIMD-backed APIs like SearchValues on daily.dev before committing to a search strategy._

### Why should you always return a rented array to ArrayPool in a finally block?

Skipping the return call in a finally block does not leak memory outright, but it starves the pool, forcing it to keep minting fresh arrays instead of reusing already-warm ones, undermining the point of pooling. Rented arrays are also recycled rather than reset, so stale data from a previous borrower may remain; pass clearArray: true or wipe it manually if that data could be sensitive or corrupt logic.

_Anyone reusing buffers with ArrayPool weighs these gotchas on daily.dev before shipping high-throughput .NET code._

## Similar posts on daily.dev

- [The Blueprint for High-Performance, Resilient .NET Applications](https://daily.dev/posts/the-blueprint-for-high-performance-resilient-net-applications-gr1arhboi) · C\# Corner · 0 upvotes · 0 comments
- [15 Advanced C\# Mistakes You’re Probably Still Making](https://daily.dev/posts/15-advanced-c-mistakes-you-re-probably-still-making-ctxsuyhsf) · ITNEXT · 36 upvotes · 2 comments
- [The .NET Tools Blog](https://daily.dev/posts/the-net-tools-blog-scy79z1yx) · JetBrains · 1 upvotes · 0 comments

---

Tags: [#performance](https://daily.dev/tags/performance), [#.net](https://daily.dev/tags/.net)

[View this post on daily.dev](https://daily.dev/posts/the-fasting-developer-memory-discipline-and-gc-awareness-in-net-5yq85h552)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"The Fasting Developer: Memory Discipline and GC Awareness in .NET","url":"https://daily.dev/posts/the-fasting-developer-memory-discipline-and-gc-awareness-in-net-5yq85h552","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/the-fasting-developer-memory-discipline-and-gc-awareness-in-net-5yq85h552"},"datePublished":"2026-07-08T12:28:46.907Z","dateModified":"2026-09-14T07:48:40.847Z","description":"A deep dive into .NET memory discipline and GC-aware coding practices. Covers how the generational garbage collector works and why short-lived objects that...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/e3e9886387ea6bf4ceceb99cc259a80e?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/e3e9886387ea6bf4ceceb99cc259a80e?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"We Are .NET","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"We Are .NET","logo":"https://media.daily.dev/image/upload/s--BsnVOa3i--/f_auto/v1718347410/logos/wearedotnet","url":"https://daily.dev/sources/wearedotnet"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/the-fasting-developer-memory-discipline-and-gc-awareness-in-net-5yq85h552","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":12},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"performance,.net","timeRequired":"PT9M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"We Are .NET","item":"https://daily.dev/sources/wearedotnet"},{"@type":"ListItem","position":3,"name":"The Fasting Developer: Memory Discipline and GC Awareness in .NET"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/the-fasting-developer-memory-discipline-and-gc-awareness-in-net-5yq85h552#faq","mainEntity":[{"@type":"Question","name":"How much memory does string.Split allocate compared to using Span<char> for parsing a string?","acceptedAnswer":{"@type":"Answer","text":"Splitting a string with string.Split typically allocates 72 to 96 bytes per call, since it creates a string array plus multiple substrings. Parsing the same value with ReadOnlySpan<char> and AsSpan/LastIndexOf/TryParse results in zero allocations, because the span operates directly on the existing string's memory instead of copying it. Developers chasing GC-driven latency spikes compare allocation costs like these on daily.dev before optimizing hot paths."}},{"@type":"Question","name":"What does SearchValues<T> in .NET 8 do differently from IndexOfAny for searching characters?","acceptedAnswer":{"@type":"Answer","text":"SearchValues<T>, introduced in .NET 8, pre-computes a vectorized lookup table once and reuses it across all subsequent searches, whereas the standard IndexOfAny(char[]) rebuilds its lookup on every call. Declaring it as a static readonly field means the pre-computation happens once at startup, and searches then run using SIMD instructions where available, giving substantially higher throughput on large inputs. Teams tuning .NET hot paths track SIMD-backed APIs like SearchValues on daily.dev before committing to a search strategy."}},{"@type":"Question","name":"Why should you always return a rented array to ArrayPool in a finally block?","acceptedAnswer":{"@type":"Answer","text":"Skipping the return call in a finally block does not leak memory outright, but it starves the pool, forcing it to keep minting fresh arrays instead of reusing already-warm ones, undermining the point of pooling. Rented arrays are also recycled rather than reset, so stale data from a previous borrower may remain; pass clearArray: true or wipe it manually if that data could be sensitive or corrupt logic. Anyone reusing buffers with ArrayPool weighs these gotchas on daily.dev before shipping high-throughput .NET code."}}]}
```

