<?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: Danial Jumagaliyev</title>
    <description>The latest articles on DEV Community by Danial Jumagaliyev (@danqzq).</description>
    <link>https://dev.to/danqzq</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%2F3522717%2F03508158-eae0-479d-9a30-05712a430902.png</url>
      <title>DEV Community: Danial Jumagaliyev</title>
      <link>https://dev.to/danqzq</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/danqzq"/>
    <language>en</language>
    <item>
      <title>Building in Public while Job Hunting: My January Dev Update</title>
      <dc:creator>Danial Jumagaliyev</dc:creator>
      <pubDate>Sun, 25 Jan 2026 05:58:48 +0000</pubDate>
      <link>https://dev.to/danqzq/building-in-public-while-job-hunting-my-january-dev-update-okf</link>
      <guid>https://dev.to/danqzq/building-in-public-while-job-hunting-my-january-dev-update-okf</guid>
      <description>&lt;p&gt;Between building a versioned Redis implementation and getting screened by AI recruiters, January has been... a lot.&lt;/p&gt;

&lt;p&gt;Let's begin with the cool new stuff.&lt;/p&gt;

&lt;h2&gt;
  
  
  New Projects
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://md.danqzq.games" rel="noopener noreferrer"&gt;&lt;strong&gt;mdspace&lt;/strong&gt;&lt;/a&gt; - easily paste and share markdown files.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I built this tool because I got tired of sharing markdown files with my peers. Either the formatting is not properly supported by the messenger or the text/file is too big. With mdspace - you paste the contents or upload the file and directly get a share link for viewing it.&lt;/li&gt;
&lt;li&gt;The tool also supports reviewing/commenting via highlighting a line in the file itself. Overall a nice personal problem I've solved for myself and I'm sure others can benefit from.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;a href="https://github.com/ElshadHu/verdis" rel="noopener noreferrer"&gt;&lt;strong&gt;verdis&lt;/strong&gt;&lt;/a&gt; - a versioned Redis.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I'm co-developing this Go project - an implementation of Redis with versioning as a core feature: key value store with multi-version concurrency control (MVCC) and historical data access.&lt;/li&gt;
&lt;li&gt;Ideal for applications that need audit trails, collaborative editing, or the ability to query data as it existed at any point in time.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;a href="https://github.com/danqzq/sharpc" rel="noopener noreferrer"&gt;&lt;strong&gt;ShaRPC&lt;/strong&gt;&lt;/a&gt; - robust RPC (Remote Procedure Call) framework for C# projects.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Since 2021, I've been dealing with RPCs in multiplayer game systems and backend services. But a thought recently came to my mind - does C# have a good RPC framework?&lt;/li&gt;
&lt;li&gt;Sure, there's gRPC but codegen is a build step, not compile-time. There's SignalR, a great alternative which meshes well with ASP.NET Core, but still comes with its own drawbacks - supporting only JSON serialization and the WebSocket protocol, with runtime codegen. A full comparison chart between frameworks is &lt;a href="https://github.com/danqzq/sharpc#why-sharpc" rel="noopener noreferrer"&gt;here&lt;/a&gt;, if you're curious.&lt;/li&gt;
&lt;li&gt; ShaRPC is built different. It's transport-agnostic, with source generator-based code generation, designed for Unity and .NET Core interoperability. As a result, you get a high-performance RPC framework for all kinds of C# projects.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Open-Source Contributions
&lt;/h2&gt;

&lt;p&gt;Made some pretty hefty pull requests to big repositories this month. Some are yet to be finalized... 💀&lt;/p&gt;

&lt;p&gt;But I can proudly say that I'm an active contributor to the open-source community. Here are some of the repositories I've been resolving issues for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/DayuanJiang/next-ai-draw-io" rel="noopener noreferrer"&gt;Next AI Draw.io&lt;/a&gt; (19.4K+ stars, TypeScript)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/ElshadHu/repo-health" rel="noopener noreferrer"&gt;Repo Health&lt;/a&gt; (100+ stars, TypeScript, active maintainer)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/ReMinecraftPE/mcpe" rel="noopener noreferrer"&gt;ReMinecraftPE&lt;/a&gt; (400+ stars, C++) - this one has been a fun (nightmarish) experience.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why Open-source?
&lt;/h3&gt;

&lt;p&gt;I'm pretty sure I answered this in &lt;a href="https://youtu.be/jk9tGmdMEEQ" rel="noopener noreferrer"&gt;my last podcast video&lt;/a&gt;, but I just think it's the best way to grow as a developer. You not only contribute to a project, you learn, you communicate, you collaborate.  You research the repository, what technical decisions were made and why.&lt;/p&gt;

&lt;p&gt;To fellow beginner software devs out there - I'm telling you, it's an easy way to get real "hands-on" experience, familiarize, experiment with new tech stacks. If the project is big enough, where it's actively maintained, has real users, and your pull request gets merged - consider that your code in production.&lt;/p&gt;

&lt;p&gt;The community is mostly welcoming, with developers being eager to help. Heck, I have &lt;a href="https://github.com/danqzq" rel="noopener noreferrer"&gt;several open-source projects&lt;/a&gt; out there - if someone tackles an existing issue in them, I would only be down to get it fully resolved and help if needed.&lt;/p&gt;

&lt;p&gt;Now, while I've been productive on the code front, I've also been seeking new job opportunities. And as you may already know, or have heard, the job market isn't great.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Job Search
&lt;/h2&gt;

&lt;p&gt;I can't say much but describe how daunting it is to apply to jobs these days and scroll through LinkedIn. Bunch of AI slop posts, fake comments... It has truly become a misery of a place.&lt;/p&gt;

&lt;p&gt;Fortunately, I am at least able to get a few interviews going for me right now, but I am literally competing with a 100 more developers. So sometimes I can't help it but wonder if I'm just wasting my time. It feels like a rat race...&lt;/p&gt;

&lt;p&gt;I hate it.&lt;/p&gt;

&lt;p&gt;The state of AI usage isn't making it any easier. I've been invited to interviews with no people present - just an AI with a robotic voice that you talk to. I would rather talk to myself, than have an LLM form an opinion about me.&lt;/p&gt;

&lt;h3&gt;
  
  
  To my fellow job seekers
&lt;/h3&gt;

&lt;p&gt;Hang in there. Times are tough. Don't think that just because you didn't pass an interview, you weren't qualified. Even if you're skilled enough, you might not be the right fit attitude-wise. That's why it's important to stay resilient and persistent.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;Expecting to drop one more thing this month - potentially a technical writeup on one of these projects.&lt;/p&gt;

&lt;p&gt;If any of this resonated with you, feel free to reach out to me. Always happy to connect with fellow devs navigating this mess together.&lt;/p&gt;

&lt;p&gt;Stay determined &amp;lt;3&lt;/p&gt;

</description>
      <category>career</category>
      <category>opensource</category>
      <category>webdev</category>
      <category>discuss</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Danial Jumagaliyev</dc:creator>
      <pubDate>Mon, 19 Jan 2026 18:13:54 +0000</pubDate>
      <link>https://dev.to/danqzq/-59bl</link>
      <guid>https://dev.to/danqzq/-59bl</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/elshadhu" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3349831%2F1d2857ab-e764-4f38-b4b5-49fcb01fa200.jpg" alt="elshadhu"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/elshadhu/communication-beats-ai-slop-in-open-source-1moo" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Communication Beats AI Slop in Open Source&lt;/h2&gt;
      &lt;h3&gt;ElshadHu ・ Jan 19&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#programming&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#ai&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#opensource&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>webdev</category>
      <category>programming</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Nobody was interested in my portfolio, so I made everyone play it instead.</title>
      <dc:creator>Danial Jumagaliyev</dc:creator>
      <pubDate>Mon, 05 Jan 2026 04:16:41 +0000</pubDate>
      <link>https://dev.to/danqzq/nobody-was-interested-in-my-portfolio-so-i-made-everyone-play-it-instead-3pjo</link>
      <guid>https://dev.to/danqzq/nobody-was-interested-in-my-portfolio-so-i-made-everyone-play-it-instead-3pjo</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/new-year-new-you-google-ai-2025-12-31"&gt;New Year, New You Portfolio Challenge Presented by Google AI&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag__cloud-run"&gt;
  &lt;iframe height="600px" src="https://danqzq-339055617326.us-central1.run.app"&gt;
  &lt;/iframe&gt;
&lt;/div&gt;




&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Controls&lt;/th&gt;
&lt;th&gt;Keyboard &amp;amp; Mouse&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Move&lt;/td&gt;
&lt;td&gt;A/D or Left/Right keys&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jump&lt;/td&gt;
&lt;td&gt;Space key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Emoji Window&lt;/td&gt;
&lt;td&gt;Q key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zoom In/Out&lt;/td&gt;
&lt;td&gt;Mouse Scroll&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Alternatively available on my website: &lt;a href="http://www.danqzq.games" rel="noopener noreferrer"&gt;www.danqzq.games&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;🎮 Challenge:&lt;/strong&gt; Can you find all the collectible cards scattered around the map? Drop a screenshot in the comments when you find them all!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F5mujp4xqcquv9bxssk73.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F5mujp4xqcquv9bxssk73.gif" alt="Portfolio Collectible Demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the next 5 minutes, you'll see why I spent 3 years building my own networking stack just to make my portfolio weirder.&lt;/p&gt;




&lt;h2&gt;
  
  
  About Me
&lt;/h2&gt;

&lt;p&gt;For the record, this is what my portfolio used to be:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fd7d3sehbyu7tnosjbntj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fd7d3sehbyu7tnosjbntj.png" alt="Dan's old portfolio site"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Working in a creative field, a boring scrollable page just didn't feel right anymore. I wanted a way to actually show what I can do, not just list it. So I took my rusty old portfolio site and turned it into an online multiplayer game world, where I can pretty much do &lt;strong&gt;ANYTHING&lt;/strong&gt; I want.&lt;/p&gt;

&lt;p&gt;I'm a game developer who believes that technology should be engaging, interactive, and boundary-pushing. This portfolio represents years of experimenting, failing, and building, from simple backends to complex multiplayer systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Portfolio in Question
&lt;/h2&gt;

&lt;p&gt;The embedded application above is a fully functional cross-platform multiplayer game that serves as my interactive portfolio. Instead of scrolling through a conventional website, visitors can explore my work through gameplay while seeing live updates of my:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Latest YouTube videos&lt;/li&gt;
&lt;li&gt;GitHub activity and contributions&lt;/li&gt;
&lt;li&gt;Indie game projects&lt;/li&gt;
&lt;li&gt;Open-source projects&lt;/li&gt;
&lt;li&gt;Random "Dan Facts of the Day"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fhpb8cr669t2j8qx37err.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fhpb8cr669t2j8qx37err.png" alt="Collectible Card Demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are also collectible cards placed around the map, each revealing pictures and information about me and my career.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media2.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%2Fyt09zbipmdiyewm9rka7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fyt09zbipmdiyewm9rka7.png" alt="Portfolio Call Button"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And there's even a special button that literally lets you call me into the world if I'm available - the kind of stuff you can't really do with a traditional portfolio.&lt;/p&gt;




&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Stack
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Game Engine (client-side):&lt;/strong&gt; Unity 6 (WebGL build with mobile support)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Networking:&lt;/strong&gt; &lt;a href="https://github.com/danqzq/dan.net" rel="noopener noreferrer"&gt;Dan.Net&lt;/a&gt; - My custom Go + WebSockets networking stack&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployment:&lt;/strong&gt; Google Cloud Run (2GB memory, 2 CPUs)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Assistant:&lt;/strong&gt; Google Antigravity for workflow optimization&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;APIs:&lt;/strong&gt; YouTube Data API, GitHub API&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server:&lt;/strong&gt; Custom Node.js HTTP server with gzip handling&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why I Built My Own Networking Stack
&lt;/h3&gt;

&lt;p&gt;Here's the thing: I didn't use some off-the-shelf multiplayer solution. Everything from the core gameplay logic and statistics displays down to the networking layer was built by me. Yes, including the entire networking stack: &lt;strong&gt;&lt;a href="https://github.com/danqzq/dan.net" rel="noopener noreferrer"&gt;Dan.Net&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;FUN FACT:&lt;/strong&gt; I drew quite a good amount of art assets as well, using &lt;a href="https://www.aseprite.org" rel="noopener noreferrer"&gt;Aseprite&lt;/a&gt;. All apart from some random PNGs for the skins and the &lt;a href="https://edermunizz.itch.io/pixel-art-plataformer-painted-style" rel="noopener noreferrer"&gt;tile-set art&lt;/a&gt;. The music is the &lt;a href="https://open.spotify.com/track/06ATooCLq2lm8tgFGE7scT?si=bd3cca3e67214f37" rel="noopener noreferrer"&gt;Toyota Corolla 2008&lt;/a&gt; theme. Please do not question the choice of music ;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This portfolio is actually the culmination of a 4 year journey into multiplayer systems:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2021:&lt;/strong&gt; I started with &lt;a href="https://www.photonengine.com" rel="noopener noreferrer"&gt;Photon Engine&lt;/a&gt;, made some games, but felt like I was just calling functions without understanding what was happening under the hood.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2022:&lt;/strong&gt; I went down the rabbit hole. I experimented with Python/Flask, built my &lt;a href="https://danqzq.itch.io/leaderboard-creator" rel="noopener noreferrer"&gt;Leaderboard Creator&lt;/a&gt; tool (now one of the highest-rated on itch.io), tried PHP, moved to Node.js and WebSockets. By late 2022, the idea for Dan.Net was born.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2023:&lt;/strong&gt; The grind. I remember spending three straight days debugging a multithreading race condition. Just me, the debugger, and this cursed bug. When it finally worked, those three days became some of the most rewarding of my life.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2025:&lt;/strong&gt; Finally, I pushed Dan.Net to a stable, production-ready state. Ready to power real projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  How the Multiplayer Actually Works
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fjnvsi4kcq2fo1ga1s7he.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fjnvsi4kcq2fo1ga1s7he.gif" alt="Multiplayer Demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All players connect to a central server hosted in the cloud. Here's the simplified flow:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Room System:&lt;/strong&gt; Players are able to create or join rooms using a room name. You can think of rooms as "player pools" or "matches" in a game, where players are able to gather together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Event-based Networking:&lt;/strong&gt; When something important happens (player joins, picks up a card, changes their skin), that player sends a "buffered event" to the server. When the player reacts with an emoji, that's sending a "direct event". The server then broadcasts it to everyone else who needs to know about it (the other players in the room).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stream-based Networking:&lt;/strong&gt; Every few milliseconds, each player sends their current position to the server. The server aggregates all positions and sends back updates about where everyone else is on the map.&lt;/p&gt;

&lt;p&gt;Under the hood, there's interpolation, latency compensation, bandwidth optimization - all that fun stuff :)&lt;/p&gt;

&lt;p&gt;But at its core, it's about keeping everyone's view of the world in sync.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploying to Google Cloud Run (The Hard Part)
&lt;/h3&gt;

&lt;p&gt;Unity's WebGL builds use gzip compression, which sounds great until you try to deploy them. The challenge: browsers need specific HTTP headers to decompress these files correctly, and Cloud Run doesn't set them by default.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Solution:&lt;/strong&gt; I built a custom Node.js HTTP server that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Detects &lt;code&gt;.gz&lt;/code&gt; files and sets &lt;code&gt;Content-Encoding: gzip&lt;/code&gt; headers&lt;/li&gt;
&lt;li&gt;Maintains correct MIME types for WebAssembly, JavaScript, and data files&lt;/li&gt;
&lt;li&gt;Handles CORS properly for cross-origin requests&lt;/li&gt;
&lt;li&gt;Serves the 36MB build efficiently with proper caching&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This was one of those problems where Google Antigravity saved my time by a lot, helping me debug header configurations and optimize the server setup.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where Google Antigravity Helped Me Most
&lt;/h3&gt;

&lt;p&gt;I used &lt;strong&gt;Google Antigravity&lt;/strong&gt; throughout development, particularly for:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dan.Net Improvements:&lt;/strong&gt; Refining how the Unity client communicates with my Go backend, especially around WebSocket connection handling and state synchronization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cloud Run Debugging:&lt;/strong&gt; Troubleshooting why my Unity build wasn't loading correctly (it was the headers). Antigravity helped me understand the relationship between Unity's compression, HTTP headers, and browser requirements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;API Integration:&lt;/strong&gt; Implementing the YouTube and GitHub APIs securely without exposing keys or creating vulnerabilities. The dynamic boards that show my latest videos and contributions wouldn't work without proper API setup.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Ffspvpwlnw34noz98aqpk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Ffspvpwlnw34noz98aqpk.png" alt="YouTube API Integration"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What I'm Most Proud Of
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Building Dan.Net from Scratch
&lt;/h3&gt;

&lt;p&gt;Creating my own Go-based networking solution and successfully integrating it with Unity for cross-platform multiplayer. This demonstrates full-stack capabilities spanning from low-level networking protocols to high-level game development in my journey. Check out &lt;a href="https://github.com/danqzq/dan.net" rel="noopener noreferrer"&gt;Dan.Net&lt;/a&gt; to see the implementation.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Breaking the Portfolio Mold
&lt;/h3&gt;

&lt;p&gt;This isn't just about showing what I've done - it's about showing what I &lt;em&gt;can do&lt;/em&gt;. A true portfolio shouldn't be a static page; it should be an experience that reflects your skills and personality. When I said I can do ANYTHING I want here, I meant it.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Real-Time, Living Portfolio
&lt;/h3&gt;

&lt;p&gt;The dynamic boards update automatically based on my activity - my latest YouTube videos and recent GitHub activity, so the world always feels alive and current. The "Dan Fact of the Day" changes daily. This means visitors always see fresh content without me manually updating anything.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Cross-Platform Multiplayer Experience
&lt;/h3&gt;

&lt;p&gt;Thanks to Unity 6's improved web support, the game works seamlessly on desktop, mobile, and web browsers. The entire experience is powered by Dan.Net, demonstrating not just front-end skills but also understanding of networking protocols, state management, distributed systems, and backend architecture.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Interactive Features You Can't Do Elsewhere
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You can hit a button that calls me into the world. I'll join if I'm available. ;)&lt;/li&gt;
&lt;li&gt;Or the collectible cards that reveal information as you explore. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are the kinds of creative features that make this portfolio memorable and engaging.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F2roobptxon8ydlv3wcac.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F2roobptxon8ydlv3wcac.png" alt="GitHub API Integration"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Philosophy Behind It
&lt;/h2&gt;

&lt;p&gt;If there's one piece of advice I'd give to anyone, whether you're in a creative line of work or deeply technical, it would be: &lt;strong&gt;share your work, and document your journey&lt;/strong&gt;. Be proud of what you've built and what you're still building. Don't hesitate to put yourself out there.&lt;/p&gt;

&lt;p&gt;Here's the thing: we learn by watching each other. When you share your work, the messy parts included - you're giving someone else permission to try. Your story might be exactly what someone needs to take their own first step. Sometimes seeing one person figure it out is enough to make us think "I could do that too."&lt;/p&gt;

&lt;p&gt;Nothing you learn ever really goes to waste. It just shows up in the next crazy idea. To me my portfolio is: years of experiments, failed projects, and learning moments all coming together into something I'm genuinely proud of.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Try it out and let me know what you think in the comments! And if you're interested in game development, networking systems, open-source development, or just want to hang out - feel free to reach out to me via &lt;a href="https://discord.gg/cyfJUjBGgK" rel="noopener noreferrer"&gt;my Discord server&lt;/a&gt; — I'd love to connect!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do you want to see more behind-the-scenes content, weird prototypes, and devlogs about this portfolio world evolving over time? Check out my &lt;a href="https://youtube.com/@danqzq" rel="noopener noreferrer"&gt;YouTube channel&lt;/a&gt; and &lt;a href="https://github.com/danqzq" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>googleaichallenge</category>
      <category>portfolio</category>
      <category>gemini</category>
    </item>
    <item>
      <title>C# Performance Optimization: Using Span&lt;T&gt; and stackalloc to Eliminate Allocations</title>
      <dc:creator>Danial Jumagaliyev</dc:creator>
      <pubDate>Thu, 04 Dec 2025 05:04:46 +0000</pubDate>
      <link>https://dev.to/danqzq/c-performance-optimization-using-span-and-stackalloc-to-eliminate-allocations-ikc</link>
      <guid>https://dev.to/danqzq/c-performance-optimization-using-span-and-stackalloc-to-eliminate-allocations-ikc</guid>
      <description>&lt;p&gt;Runtime memory handling is a crucial part of writing software, which heavily impacts the performance of your program. I think for every language there comes this layer of responsibility, but how it is delegated between the developer and the language is different.&lt;/p&gt;

&lt;p&gt;In the case of using C/C++ - memory allocation is totally under the control of the developer. Whereas in languages like JavaScript, Python, Go, Java, where memory is managed - developers rarely need to worry about where an array is stored in memory, it's the duty of the language's runtime system to decide when to deallocate data that is no longer used. And this is where &lt;strong&gt;garbage collection&lt;/strong&gt; comes into play.&lt;/p&gt;

&lt;p&gt;C# (.NET platform) is known for its heavy GC (garbage collection) of dynamic (heap-allocated) resources. The process is straightforward - garbage collection automatically identifies unused memory (garbage) and frees it to be reused, efficiently recycling resources.&lt;/p&gt;

&lt;p&gt;This article explores how &lt;code&gt;stackalloc&lt;/code&gt; and &lt;code&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt; eliminate garbage collection pressure in performance-critical C# code, using real optimization examples from &lt;a href="https://github.com/danqzq/dan.net" rel="noopener noreferrer"&gt;Dan.Net&lt;/a&gt;, my Unity networking library. By the end, you'll understand when and how to apply these techniques to reduce allocations by orders of magnitude in hot code paths.&lt;/p&gt;

&lt;h2&gt;
  
  
  Memory Allocation in C&lt;code&gt;#&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;By default, the data of all reference types (classes, arrays, strings, delegates and interfaces) are allocated on the heap. The references to heap objects, however, live on stack or heap, but value types stay on stack unless boxed (converted into &lt;code&gt;object&lt;/code&gt; type):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Location&lt;/th&gt;
&lt;th&gt;Storage&lt;/th&gt;
&lt;th&gt;GC Impact&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Local reference variable&lt;/td&gt;
&lt;td&gt;Stack&lt;/td&gt;
&lt;td&gt;None (reference only)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Class field reference&lt;/td&gt;
&lt;td&gt;Heap&lt;/td&gt;
&lt;td&gt;Collected with object ​&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Local value type&lt;/td&gt;
&lt;td&gt;Stack&lt;/td&gt;
&lt;td&gt;None unless boxed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;On one hand, this is amazing. As the developer, you focus more on writing core logic and you get to easily structure your code in meaningful ways; you don't have to care about ensuring runtime safety and clean up dynamic memory resources after use - this job is handled automatically by the garbage collector, which is part of the &lt;a href="https://learn.microsoft.com/en-us/dotnet/standard/clr" rel="noopener noreferrer"&gt;.NET CLR (Common Language Runtime)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, this could easily become a recipe for disaster in terms of performance. A developer who isn't familiar with the .NET ecosystem is likely to write code that may look good on the surface - but could be causing unnecessary memory allocations underneath the hood, reducing execution speed as a result.&lt;/p&gt;

&lt;p&gt;I, personally, used to make this mistake often when working with .NET in my first few years of building Unity projects. I would receive performance feedback that I was using too many LINQ (Language Integrated Query) statements, which can cause excessive garbage collection, especially in the older .NET versions. In those days, I barely thought about the importance of memory management.&lt;/p&gt;

&lt;p&gt;For instance, I would write code like this in a hot path that executed every frame:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ Allocates multiple enumerators and intermediate collections&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;activeEnemies&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;enemies&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;health&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OrderBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;distanceToPlayer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each LINQ operation allocates an enumerator, and &lt;code&gt;ToList()&lt;/code&gt; allocates a new list. At 60 frames per second, this becomes 60 allocations per second per operation, triggering frequent garbage collections that cause frame drops.&lt;/p&gt;




&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;I was recently enjoying my weekend by reviewing my personal projects, until I decided to look into Dan.Net again. It's my own networking library for Unity, operating over HTTP/WebSockets and prioritizing ease-of-development and cross-platform-ability. I have been experimenting and toying around with it for quite a while now, and made a proper release of it earlier this year on &lt;a href="https://github.com/danqzq/dan.net" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Shortly after its release, I had a friend review it for me and they gave me some honest feedback. There's more to the story that deserves its own article. But in short, I chose to optimize - not out of necessity, but passion. It was working, but not &lt;strong&gt;fast&lt;/strong&gt; enough. The drive for optimizations truly emerged within me, echoing Linus Torvalds' ethos.&lt;/p&gt;

&lt;p&gt;With AI producing more code every day, I realized that mastering the fundamentals is key for programmers to truly understand and oversee the systems we build. And this is exactly why I am writing this blog! &lt;/p&gt;

&lt;p&gt;After implementing the optimizations described in this article, Dan.Net's per-frame allocation during active network synchronization dropped significantly, from ~2.5KB to under 200 bytes - a 92% reduction. This eliminated GC stalls during 20Hz network updates, maintaining stable frame times even with 50+ networked objects.&lt;/p&gt;




&lt;h2&gt;
  
  
  About Memory
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Stack Basics
&lt;/h3&gt;

&lt;p&gt;The stack holds short-lived data like local variables and method parameters in a LIFO (Last-In, First-Out) structure, with automatic allocation/deallocation on method entry/exit. Access is fast due to its contiguous layout and CPU cache affinity, not because it's "in the cache" - both stack and heap reside in RAM. Value types (structs, primitives) live here unless boxed or embedded in heap objects.​&lt;/p&gt;

&lt;p&gt;The stack has a limited size - typically 1MB per thread on Windows and 8MB on Linux/macOS by default (these are operating system defaults, not Unity-specific). Unity's stack behavior inherits from the underlying .NET runtime and platform. Exceeding this capacity results in a &lt;code&gt;StackOverflowException&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Heap Basics
&lt;/h3&gt;

&lt;p&gt;The heap manages dynamic, long-lived objects via garbage collection, allowing flexible sizing but with slower access from indirection and GC pauses (periods when unreferenced memory gets cleaned up by the garbage collector). It grows as needed (system-limited), unlike the stack's fixed per-thread quota.​ As mentioned, this is where referenced types (classes, arrays, etc) reside.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stack Limitations
&lt;/h3&gt;

&lt;p&gt;To make it more clear, let's represent stack memory's LIFO behavior visually:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stack (capacity: 6)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;(empty)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(empty, next insertion goes here)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;4&lt;/code&gt; (first to be out, last in)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;3&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;1&lt;/code&gt; (last to be out, first in)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;After two more insertions, this stack would become full. Assuming no deallocation occurs - the next allocation attempt would lead to a &lt;strong&gt;stack overflow&lt;/strong&gt;. Real stack memory in C# manages method call frames, local variables, and return addresses in this LIFO manner, with each method invocation "pushing" a new frame and "popping" it off when returning.&lt;/p&gt;

&lt;h2&gt;
  
  
  C# History Lesson
&lt;/h2&gt;

&lt;p&gt;C# provides &lt;code&gt;stackalloc&lt;/code&gt; for explicit stack allocation of temporary buffers. Over time, its usability and safety have improved significantly with each major C# release, especially since C# 7.2.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Danger Zone
&lt;/h3&gt;

&lt;p&gt;Initially, &lt;code&gt;stackalloc&lt;/code&gt; could only be used in conjunction with the &lt;code&gt;unsafe&lt;/code&gt; modifier. Methods can be defined under an &lt;code&gt;unsafe&lt;/code&gt; context, which signals the C# compiler &lt;em&gt;"hey, we're about to do something illegal here"&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Program&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;unsafe&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&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;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="c1"&gt;// Allocate a block of memory for 5 integers on the stack&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;numbers&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;stackalloc&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;length&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

        &lt;span class="c1"&gt;// Use pointer arithmetic to access and populate the memory block&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&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="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;length&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="p"&gt;*(&lt;/span&gt;&lt;span class="n"&gt;numbers&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="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// = numbers[i]&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Read the values back using array-like pointer syntax&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&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="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;length&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="c1"&gt;// Pointer element access operator p[n] is evaluated as *(p + n)&lt;/span&gt;
            &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"numbers[&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="s"&gt;]: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;numbers&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="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Memory is automatically discarded when the method returns&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;blockquote&gt;
&lt;p&gt;To run this code for yourself, you must modify the &lt;code&gt;.csproj&lt;/code&gt; file in your C# project to include &lt;code&gt;&amp;lt;AllowUnsafeBlocks&amp;gt;true&amp;lt;/AllowUnsafeBlocks&amp;gt;&lt;/code&gt; within a &lt;code&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/code&gt;. Here's the expected output:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;numbers[0]: 0
numbers[1]: 10
numbers[2]: 20
numbers[3]: 30
numbers[4]: 40
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, &lt;code&gt;stackalloc&lt;/code&gt; used to be limited to allocating memory for pointers, which made it primarily a low-level, performance-focused feature suitable for advanced developers requiring fine control over memory, similar to variable-length arrays or the &lt;code&gt;alloca()&lt;/code&gt; function in C/C++.&lt;/p&gt;

&lt;p&gt;If the above-written code seems confusing to you, I highly recommend touching up on pointers and arrays in C, as C# borrows the same logic from there.&lt;/p&gt;

&lt;h3&gt;
  
  
  When the stack was truly stacking
&lt;/h3&gt;

&lt;p&gt;It's only when &lt;a href="https://learn.microsoft.com/dotnet/csharp/whats-new/csharp-version-history#c-version-72" rel="noopener noreferrer"&gt;C# 7.2&lt;/a&gt; and &lt;a href="https://learn.microsoft.com/dotnet/csharp/whats-new/csharp-version-history#c-version-73" rel="noopener noreferrer"&gt;7.3&lt;/a&gt; released that &lt;code&gt;stackalloc&lt;/code&gt; became usable outside of &lt;code&gt;unsafe&lt;/code&gt; contexts, &lt;em&gt;only&lt;/em&gt; if the result was immediately converted to a &lt;code&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt; or &lt;code&gt;ReadOnlySpan&amp;lt;T&amp;gt;&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// C# 7.2&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;dataArray&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&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;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="n"&gt;Span&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;dataSpan&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dataArray&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;dataSpan&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="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// dataArray[0] is modified&lt;/span&gt;

&lt;span class="c1"&gt;// dataArray is now {100, 2, 3, 4, 5}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can think of spans as "views" that allow access to memory regions like arrays, strings, or stack buffers, making them very lightweight, drastically reducing garbage collection pressure and improving speed in data-intensive code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benchmarking Pitfalls: The JIT Optimizer
&lt;/h3&gt;

&lt;p&gt;Before diving into span performance comparisons, it's critical to understand a common benchmarking problem. Modern JIT (Just-in-time) compilers are extremely aggressive about eliminating "dead code" - code whose results are never used. When benchmarking span operations, if you don't actually consume the results, the compiler may eliminate the entire operation, giving you misleading &lt;code&gt;0.0000 ns&lt;/code&gt; execution times.&lt;/p&gt;

&lt;p&gt;I encountered this exact issue when benchmarking the span optimizations. The solution is using &lt;code&gt;BenchmarkDotNet&lt;/code&gt;'s &lt;a href="https://benchmarkdotnet.org/api/BenchmarkDotNet.Engines.Consumer.html" rel="noopener noreferrer"&gt;&lt;code&gt;Consumer&lt;/code&gt;&lt;/a&gt; class, which signals to the compiler that values are being observed, preventing optimization away. Always verify your benchmarks produce realistic non-zero timings before trusting the results.&lt;/p&gt;

&lt;p&gt;I wrote these two methods which serve the same purpose - to retrieve top 3 scores from a &lt;code&gt;scores&lt;/code&gt; array of integers. I benchmarked these methods using &lt;a href="https://benchmarkdotnet.org" rel="noopener noreferrer"&gt;&lt;code&gt;BenchmarkDotNet&lt;/code&gt;&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="c1"&gt;// class SpanBenchmark&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;length&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;private&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;scores&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&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;length&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// Constructor to initialize scores array with values&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;SpanBenchmark&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&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="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;length&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="n"&gt;scores&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="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="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Benchmark&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="nf"&gt;GetTop3Scores_Copy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ❌ Traditional: Copy top 3 scores = heap allocation every time!&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;top3Copy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&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;3&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="n"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;top3Copy&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;3&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;top3Copy&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;Benchmark&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Span&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetTop3Scores_Span&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ✅ C# 7.2: Slice original array = ZERO heap allocations&lt;/span&gt;
    &lt;span class="n"&gt;Span&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;allScores&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;Span&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;top3&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;allScores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&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;top3&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Results:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BenchmarkDotNet v0.15.8, macOS Tahoe 26.1 (25B78) [Darwin 25.1.0]
Apple M5, 1 CPU, 10 logical and 10 physical cores
.NET SDK 9.0.306
  [Host]     : .NET 9.0.10 (9.0.10, 9.0.1025.47515), Arm64 RyuJIT armv8.0-a
...
| Method  | Mean      | Error     | StdDev    | Gen0   | Allocated |
|---------|-----------|-----------|-----------|--------|-----------|
| ...Copy | 4.0631 ns | 0.0274 ns | 0.0229 ns | 0.0048 |      40 B |
| ...Span | 0.2082 ns | 0.0202 ns | 0.0189 ns |      - |         - |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can clearly see that the &lt;code&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt; approach is allocating no dynamic memory at all, meaning it's completely utilizing the stack within the method. The &lt;code&gt;Gen0&lt;/code&gt; column shows Generation 0 garbage collections per 1000 operations - the copy method triggers GC pressure while the span approach has zero impact.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt; class comes with a powerful method - &lt;code&gt;Slice&lt;/code&gt;, thanks to which the span method is running faster in the first place. See the &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.span-1.slice?view=net-10.0#system-span-1-slice(system-int32-system-int32)" rel="noopener noreferrer"&gt;function specification here&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  We can be safe... and go faster?
&lt;/h4&gt;

&lt;p&gt;We are making use of &lt;code&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt;, where the spans can be of type &lt;code&gt;ReadOnlySpan&amp;lt;T&amp;gt;&lt;/code&gt; since they aren't modified at all. The main usage of &lt;code&gt;ReadOnlySpan&amp;lt;T&amp;gt;&lt;/code&gt; is not mainly dedicated to increasing performance, but rather to communicate the fact that the span is fully immutable.&lt;/p&gt;

&lt;p&gt;However, after duplicating and modifying the span method (this time using &lt;code&gt;ReadOnlySpan&amp;lt;T&amp;gt;&lt;/code&gt; instead of &lt;code&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt; as the type) - I noticed there is about a ~20% reduction in execution time, as evidenced by the benchmark results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;| Method          | Mean      | Error     | StdDev    | Allocated |
|-----------------|-----------|-----------|-----------|-----------|
| ...Span         | 0.1880 ns | 0.0266 ns | 0.0273 ns |         - |
| ...ReadOnlySpan | 0.1460 ns | 0.0142 ns | 0.0126 ns |         - |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The performance improvement from &lt;code&gt;ReadOnlySpan&amp;lt;T&amp;gt;&lt;/code&gt; comes from compiler optimizations around immutability guarantees. The JIT compiler can eliminate bounds checks and enable more aggressive inlining when it knows the data won't be modified, reducing instruction count and improving CPU pipeline efficiency.&lt;/p&gt;

&lt;h4&gt;
  
  
  Execution Time Comparison (lower is better)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Array.Copy      █████████████████████████ 4.06 ns
Span&amp;lt;T&amp;gt;         ██ 0.19 ns
ReadOnlySpan&amp;lt;T&amp;gt; █ 0.15 ns
                |
                0     1     2     3     4 (nanoseconds)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, this might not seem like a practical example, but imagine a similar case with significantly more function calls and larger array sizes. Would it make sense to allocate extra dynamic resources where avoidable? We'll later dive into more use cases, coming from my own experience.&lt;/p&gt;




&lt;h3&gt;
  
  
  Syntax Improvements
&lt;/h3&gt;

&lt;p&gt;Moving on to C# 7.3, it came with support for array initializer syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// C# 7.2 and before:&lt;/span&gt;
&lt;span class="n"&gt;Span&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;stackalloc&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="n"&gt;arr&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="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;67&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;68&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;69&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// C# 7.3 and after:&lt;/span&gt;
&lt;span class="n"&gt;Span&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;stackalloc&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;67&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;68&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;69&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This significantly reduced the verbosity and error-proneness of low-level buffer initialization.&lt;/p&gt;

&lt;p&gt;It only got better from here though, as &lt;a href="https://learn.microsoft.com/en-ca/dotnet/csharp/whats-new/csharp-version-history#c-version-80" rel="noopener noreferrer"&gt;C# 8&lt;/a&gt; introduced &lt;code&gt;stackalloc&lt;/code&gt; support in more nested expression contexts, such as inside conditionals or as part of larger expressions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;length&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="n"&gt;Span&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;&amp;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;length&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="m"&gt;1024&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;stackalloc&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;length&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&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;length&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://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-12" rel="noopener noreferrer"&gt;C# 12&lt;/a&gt; introduced collection expressions, a concise syntax that often compiles to stackalloc for small Span eliminating explicit keywords entirely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// C# 12: Compiles to stackalloc for small spans (zero heap!)&lt;/span&gt;
&lt;span class="n"&gt;Span&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// Automatic stack allocation&lt;/span&gt;

&lt;span class="c1"&gt;// Same as:&lt;/span&gt;
&lt;span class="n"&gt;Span&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;arr2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;stackalloc&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;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;  &lt;span class="c1"&gt;// Verbose equivalent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Applying the Knowledge
&lt;/h2&gt;

&lt;p&gt;Now back onto Dan.Net and where the memory optimizations came in. After a first run-through of enhancing the library, I made it fully operate with binary data. Events and streaming data were now being compressed and serialized into a special binary format before sending to the server, and, subsequently, incoming data was being deserialized and decompressed into data to be used on the client.&lt;/p&gt;

&lt;p&gt;These processes required dealing with lots of allocation of bytes and bit manipulation for ensuring fast performance, but I was avoiding the memory overhead and focused on implementing the new binary protocol initially. Only at a second glance I took the decision to begin approaching memory optimizations, which involved heap allocation reduction.&lt;/p&gt;

&lt;p&gt;Let's take a look at some of those examples:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Range Calculations
&lt;/h3&gt;

&lt;p&gt;Below is a code snippet from my &lt;code&gt;Quaternion&lt;/code&gt; compression logic, executed every time before sending data of a networked object's rotation&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;largestIndex&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="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;largestValue&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;components&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="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&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;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;4&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="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;abs&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;components&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;abs&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;largestValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;largestValue&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;largestIndex&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;q&lt;/code&gt; here is a &lt;code&gt;Quaternion&lt;/code&gt; struct parameter, which contains the data of the current rotation of a networked game object. Quaternions represent 3D rotations as four floats, but can be transmitted in just 7 bytes by using the "smallest-three" compression algorithm - since quaternions are unit-length (x² + y² + z² + w² = 1), we can omit the largest component and reconstruct it from the other three, saving 9 bytes per rotation.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;components&lt;/code&gt; array is being allocated on the heap. It's only used locally for performing a simple calculation as shown above. So it's safe to convert the array into a stack-allocated span:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;Span&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;stackalloc&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Might seem insignificant, but this function is to be executed at a frequency of 20 Hz. That's 20 times a second, which is 20 memory allocations of 4 floating point numbers -&amp;gt; 320 byte allocation/sec.&lt;/p&gt;

&lt;p&gt;And that's just for one network-synchronized game object. What if we had more? In &lt;strong&gt;real-time networking&lt;/strong&gt; scenarios like my library's streaming system, these optimizations matter.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In a similar fashion, I dealt with Quaternion &lt;em&gt;decompression&lt;/em&gt; using spans.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  2. Performant Chat Command Parsing
&lt;/h3&gt;

&lt;p&gt;I believe this is where Spans truly shine. Consider a multiplayer game built with Dan.Net where players send chat commands at high frequency. Commands like &lt;code&gt;"/say Hello everyone!"&lt;/code&gt;, &lt;code&gt;"/join lobby-01"&lt;/code&gt;, or &lt;code&gt;"/trade player123 50"&lt;/code&gt; need to be parsed into command names and arguments - and this happens &lt;strong&gt;100+ times per second in active game lobbies&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The traditional string-based approach allocates heavily:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ Traditional: Multiple string allocations per command&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;DanNetEvent&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnSendChatCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Example: "/say Hello everyone!"&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartsWith&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="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Not a command&lt;/span&gt;

    &lt;span class="c1"&gt;// Remove the leading "/" &lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;withoutSlash&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Find first space to separate command from args&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;spaceIndex&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;withoutSlash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IndexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;' '&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spaceIndex&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Execute command with no arguments (e.g., "/help")&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Split command and arguments&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;commandName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;withoutSlash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Substring&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="n"&gt;spaceIndex&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;withoutSlash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spaceIndex&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Execute command with arguments&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Every &lt;code&gt;Substring()&lt;/code&gt; call allocates a new string by copying characters&lt;/strong&gt;. For the example &lt;code&gt;"/say Hello everyone!"&lt;/code&gt;, that's &lt;strong&gt;4 heap allocations&lt;/strong&gt; (withoutSlash, commandName, arguments, plus potential &lt;code&gt;string.Empty&lt;/code&gt;) per message. At 100 messages/sec, that's &lt;strong&gt;400 allocations/sec&lt;/strong&gt; just for command parsing.&lt;/p&gt;

&lt;p&gt;Here's the span-based rewrite that eliminates all intermediate allocations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ✅ Span-based: ZERO intermediate allocations&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;DanNetEvent&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnSendChatCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ReadOnlySpan&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Example: "/say Hello everyone!"&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&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="n"&gt;message&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="p"&gt;!=&lt;/span&gt; &lt;span class="sc"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Not a command&lt;/span&gt;

    &lt;span class="c1"&gt;// Slice away the leading "/" - no allocation, just pointer arithmetic&lt;/span&gt;
    &lt;span class="n"&gt;ReadOnlySpan&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;withoutSlash&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Find first space to separate command from args&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;spaceIndex&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;withoutSlash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IndexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;' '&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spaceIndex&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Execute command with no arguments (e.g., "/help")&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Slice command and arguments - still no allocation!&lt;/span&gt;
    &lt;span class="n"&gt;ReadOnlySpan&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;commandName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;withoutSlash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Slice&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="n"&gt;spaceIndex&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;ReadOnlySpan&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;withoutSlash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spaceIndex&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Only allocate when storing final results&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;finalCommand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;finalArguments&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;commandName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

    &lt;span class="c1"&gt;// Execute command with arguments&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The span version performs all slicing operations as lightweight "views" into the original string - zero copies, zero heap allocations until the final &lt;code&gt;ToString()&lt;/code&gt; calls. The &lt;code&gt;IndexOf()&lt;/code&gt; and &lt;code&gt;Slice()&lt;/code&gt; operations are pointer arithmetic, making them extremely fast.&lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;ReadOnlySpan&amp;lt;char&amp;gt;&lt;/code&gt; as a parameter (instead of &lt;code&gt;string&lt;/code&gt;) allows callers to pass string slices, stack-allocated buffers, or even substrings without allocation - the method works with any contiguous character memory.&lt;/p&gt;

&lt;h4&gt;
  
  
  Bonus Optimization
&lt;/h4&gt;

&lt;p&gt;For known command prefixes, you can avoid string allocation entirely by using &lt;code&gt;SequenceEqual&lt;/code&gt; for comparisons:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Check if command is "/help" without allocating strings&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;commandName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SequenceEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"help"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;ShowHelpMenu&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Check if command is "/say" &lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;commandName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SequenceEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"say"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;SayMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&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;This pattern allows you to handle common commands &lt;strong&gt;completely allocation-free&lt;/strong&gt; by processing spans directly instead of converting to strings.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Vector3 Compression Pattern
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;WriteVector3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BinaryWriter&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;Vector3&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BitConverter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BitConverter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BitConverter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;z&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;This method converts a 3D vector (a struct containing three floating point values &lt;code&gt;x&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt; and &lt;code&gt;z&lt;/code&gt;) into binary form.&lt;/p&gt;

&lt;p&gt;Looks good on the surface, right? Not until you realize &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.bitconverter.getbytes" rel="noopener noreferrer"&gt;&lt;code&gt;BitConverter.GetBytes()&lt;/code&gt;&lt;/a&gt; returns a heap allocated byte array.&lt;/p&gt;

&lt;p&gt;The solution? Stackalloc a buffer of 12 bytes, then explicitly write the Vector3 values into the three 4 byte segments of the buffer, since the values are all 32-bit (equal to 4 bytes) floating point numbers. And we accomplish this with the help of slicing and the &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.bitconverter.trywritebytes" rel="noopener noreferrer"&gt;&lt;code&gt;BitConverter.TryWriteBytes()&lt;/code&gt;&lt;/a&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;WriteVector3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BinaryWriter&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;Vector3&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Span&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;stackalloc&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;12&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="n"&gt;BitConverter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryWriteBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Slice&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;4&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;BitConverter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryWriteBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;BitConverter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryWriteBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Write&lt;/span&gt;&lt;span class="p"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  There is a Problem
&lt;/h4&gt;

&lt;p&gt;This approach only works in .NET 5.0 and greater, that's when spans began to be adopted in the .NET ecosystem. My library is used on top of Unity.&lt;/p&gt;

&lt;p&gt;Unity still mostly targets .NET Standard 2.1, only unlocking the ability to use newer versions of .NET starting from Unity 6. Luckily there is a sub-optimal solution - using conditional compilation, which allows libraries to target multiple platforms while using the most efficient APIs available on each.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#if NET5_0_OR_GREATER
&lt;/span&gt;    &lt;span class="n"&gt;Span&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;stackalloc&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;12&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="n"&gt;BitConverter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryWriteBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Slice&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;4&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;BitConverter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryWriteBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;BitConverter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryWriteBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Has Span overload in .NET 5+&lt;/span&gt;
&lt;span class="cp"&gt;#else
&lt;/span&gt;    &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="cp"&gt;#endif
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, when compiled for .NET 5+, this gets zero-allocation stackalloc; any version lower, and it uses the traditional (but still efficient) approach.&lt;/p&gt;




&lt;h2&gt;
  
  
  Safety Considerations
&lt;/h2&gt;

&lt;p&gt;While &lt;code&gt;stackalloc&lt;/code&gt; is powerful, it requires careful usage to avoid crashes and undefined behavior:&lt;/p&gt;

&lt;h3&gt;
  
  
  Stack Overflow Risks
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Never use &lt;code&gt;stackalloc&lt;/code&gt; with user-controlled sizes or variable-length inputs.&lt;/strong&gt; The stack is limited (typically 1MB per thread), and exceeding it causes unrecoverable &lt;code&gt;StackOverflowException&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ DANGEROUS: User could cause stack overflow&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;userSize&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GetUserInput&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;Span&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;stackalloc&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;userSize&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ SAFE: Guard with size check and fallback to heap&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GetUserInput&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;Span&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;&amp;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;size&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="m"&gt;1024&lt;/span&gt; 
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;stackalloc&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;size&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&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;size&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Keep Allocations Under 8KB
&lt;/h3&gt;

&lt;p&gt;For cross-platform safety, keep &lt;code&gt;stackalloc&lt;/code&gt; sizes under &lt;strong&gt;8KB&lt;/strong&gt; (8192 bytes). Larger allocations risk stack overflow on platforms with smaller stack sizes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ✅ Safe for all platforms&lt;/span&gt;
&lt;span class="n"&gt;Span&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;smallBuffer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;stackalloc&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;4096&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// ⚠️ Risky on some platforms&lt;/span&gt;
&lt;span class="n"&gt;Span&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;largeBuffer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;stackalloc&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;65536&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// 64KB&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Never Use stackalloc in Loops
&lt;/h3&gt;

&lt;p&gt;Repeated stack allocations in loops don't get "cleaned up" until the method returns, effectively leaking stack space:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ DANGEROUS: Stack grows with each iteration&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&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="n"&gt;i&lt;/span&gt; &lt;span class="p"&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="p"&gt;++)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Span&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;stackalloc&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// 1MB total!&lt;/span&gt;
    &lt;span class="nf"&gt;ProcessData&lt;/span&gt;&lt;span class="p"&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="c1"&gt;// ✅ SAFE: Allocate once outside loop&lt;/span&gt;
&lt;span class="n"&gt;Span&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;stackalloc&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&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="n"&gt;i&lt;/span&gt; &lt;span class="p"&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="p"&gt;++)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;ProcessData&lt;/span&gt;&lt;span class="p"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Debugging Challenges
&lt;/h3&gt;

&lt;p&gt;Stack-allocated memory doesn't appear in memory profilers or GC diagnostics, making debugging harder. Always profile both allocation counts (heap) and execution time (stack) to verify optimizations work as expected.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Today, &lt;code&gt;stackalloc&lt;/code&gt; is a core feature for scenarios where maximum speed and minimum allocation overhead matter, like parsing or serialization. Developers are encouraged to use it with &lt;code&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt; to maintain safety, only falling back to unsafe pointer usage for the rarest high-performance cases. These optimizations reduced Dan.Net's per-frame allocation by over ~80% on average, eliminating GC stalls during 20Hz network updates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When NOT to optimize with stackalloc&lt;/strong&gt;: Don't prematurely optimize. Use stackalloc only after profiling identifies allocation hotspots. For one-time setup code, IO-bound operations, or methods called &amp;lt;1000 times/sec, the complexity cost outweighs the performance benefit. Always measure with a profiler before and after.&lt;/p&gt;

&lt;p&gt;This evolution has made stack-based, high-performance memory scenarios much more approachable, while maintaining C#'s general focus on safety and productivity.&lt;/p&gt;

&lt;p&gt;If you're curious about my other works, check out my &lt;a href="https://www.danqzq.games" rel="noopener noreferrer"&gt;portfolio website&lt;/a&gt;. Dan.Net is open-source on &lt;a href="https://github.com/danqzq/dan.net" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; - contributions and feedback are welcome!&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>performance</category>
      <category>dotnet</category>
      <category>unity3d</category>
    </item>
  </channel>
</rss>
