<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged heap</title>
<link>https://coderlegion.com/tag/heap</link>
<description>Powered by Question2Answer</description>
<item>
<title>1366. Rank Teams by Votes</title>
<link>https://coderlegion.com/24947/1366-rank-teams-by-votes</link>
<description>&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;&lt;br&gt;
In a special ranking system, each voter gives a rank from highest to lowest to all teams participating in the competition.&lt;/p&gt;
&lt;p&gt;The ordering of teams is decided by who received the most position-one votes. If two or more teams tie in the first position, we consider the second position to resolve the conflict, if they tie again, we continue this process until the ties are resolved. If two or more teams are still tied after considering all positions, we rank them alphabetically based on their team letter.&lt;/p&gt;
&lt;p&gt;You are given an array of strings votes which is the votes of all voters in the ranking systems. Sort all teams according to the ranking system described above.&lt;/p&gt;
&lt;p&gt;Return a string of all teams sorted by the ranking system.&lt;/p&gt;
&lt;p&gt;Example 1:&lt;/p&gt;
&lt;p&gt;Input: votes = [&quot;ABC&quot;,&quot;ACB&quot;,&quot;ABC&quot;,&quot;ACB&quot;,&quot;ACB&quot;]&lt;br&gt;
Output: &quot;ACB&quot;&lt;br&gt;
Explanation:&lt;br&gt;
Team A was ranked first place by 5 voters. No other team was voted as first place, so team A is the first team.&lt;br&gt;
Team B was ranked second by 2 voters and ranked third by 3 voters.&lt;br&gt;
Team C was ranked second by 3 voters and ranked third by 2 voters.&lt;br&gt;
As most of the voters ranked C second, team C is the second team, and team B is the third.&lt;br&gt;
Example 2:&lt;/p&gt;
&lt;p&gt;Input: votes = [&quot;WXYZ&quot;,&quot;XYZW&quot;]&lt;br&gt;
Output: &quot;XWYZ&quot;&lt;br&gt;
Explanation:&lt;br&gt;
X is the winner due to the tie-breaking rule. X has the same votes as W for the first position, but X has one vote in the second position, while W does not have any votes in the second position.&lt;br&gt;
Example 3:&lt;/p&gt;
&lt;p&gt;Input: votes = [&quot;ZMNAGUEDSJYLBOPHRQICWFXTVK&quot;]&lt;br&gt;
Output: &quot;ZMNAGUEDSJYLBOPHRQICWFXTVK&quot;&lt;br&gt;
Explanation: Only one voter, so their votes are used for the ranking.&lt;/p&gt;
&lt;p&gt;Constraints:&lt;/p&gt;
&lt;p&gt;1 &amp;lt;= votes.length &amp;lt;= 1000&lt;br&gt;
1 &amp;lt;= votes[i].length &amp;lt;= 26&lt;br&gt;
votes[i].length == votes[j].length for 0 &amp;lt;= i, j &amp;lt; votes.length.&lt;br&gt;
votes[i][j] is an English uppercase letter.&lt;br&gt;
All characters of votes[i] are unique.&lt;br&gt;
All the characters that occur in votes[0] also occur in votes[j] where 1 &amp;lt;= j &amp;lt; votes.length.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Discussion&lt;/strong&gt;&lt;br&gt;
This problem can be solved using 2 data structures- a hashmap and a heap. We use the map to store the votes by each judge and the heap to sort the teams. We create a comparator to sort the teams and initialize the heap using it.&lt;br&gt;
We then traverse the votes array to calculate the votes and create the map.Once this is done we add the keys of the map which are the teams to the heap and pull the elements off one by one to get the final string.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Java&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Solution {
    public String rankTeams(String[] votes) {
      HashMap&amp;lt;Character,int[]&amp;gt;map=new  HashMap&amp;lt;&amp;gt;();
      String answer=&quot;&quot;;
      for(int i=0;i&amp;lt;votes.length;i++){
       String vote=votes[i];
       for(int j=0;j&amp;lt;vote.length();j++){
        char team=vote.charAt(j);
        if(!map.containsKey(team)){
         int [] counts= new int[vote.length()];
         counts[j]++;
         map.put(team,counts);
        }else{
          int [] counts =map.get(team);
          counts[j]++;
          map.replace(team,counts);
        }
       } 
      }
      PriorityQueue&amp;lt;Character&amp;gt; pq = new PriorityQueue&amp;lt;&amp;gt;((a, b) -&amp;gt; {
        int[] va = map.get(a);
        int[] vb = map.get(b);
        for (int i = 0; i &amp;lt; va.length; i++) {
            if (va[i] != vb[i]) {
            return Integer.compare(vb[i], va[i]);
             }
        }
        return Character.compare(a, b);
      });  
      for (char team : map.keySet()) pq.offer(team);
      while(!pq.isEmpty()){
       char ch=pq.poll();
       answer+=ch; 
      }
      return answer;
    }
}
&lt;/code&gt;&lt;/pre&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/24947/1366-rank-teams-by-votes</guid>
<pubDate>Wed, 19 Aug 2026 18:52:21 +0000</pubDate>
</item>
<item>
<title>Is Your Game Choking on GC Allocations?</title>
<link>https://coderlegion.com/21847/is-your-game-choking-on-gc-allocations</link>
<description>
&lt;h2 id=&quot;is-your-game-choking-on-gc-allocations-a-guide-to-zero-allocation-data-structures&quot;&gt;Is Your Game Choking on GC Allocations? A Guide to Zero-Allocation Data Structures&lt;/h2&gt;

&lt;h3 id=&quot;introduction&quot;&gt;Introduction&lt;/h3&gt;

&lt;p&gt;You&amp;rsquo;ve optimized your shaders, painstakingly batched draw calls, and even dipped your toes into Unity&amp;rsquo;s Burst Compiler and C# Job System. Yet, your game still experiences inexplicable hitches and stutters, particularly during intense moments. The silent assassin in many Unity games isn&amp;rsquo;t the GPU struggling with pixels, but the &lt;strong&gt;Garbage Collector (GC)&lt;/strong&gt; reclaiming memory from incessant, hidden allocations. Specifically, insidious &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GC.Alloc&lt;/code&gt; calls, often for temporary &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;class&lt;/code&gt;-based data structures, can disrupt your carefully crafted frame budget, leading to frustrating performance spikes.&lt;/p&gt;

&lt;p&gt;This tutorial will illuminate this common pitfall and provide a robust architectural solution: embracing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;struct&lt;/code&gt; types combined with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt; for transient data. By understanding and applying these principles, you can virtually eliminate many &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GC.Alloc&lt;/code&gt; calls from your high-frequency game logic, leading to buttery-smooth frame rates and a fundamentally cleaner, faster codebase.&lt;/p&gt;

&lt;h3 id=&quot;the-culprit-unnecessary-class-allocations&quot;&gt;The Culprit: Unnecessary Class Allocations&lt;/h3&gt;

&lt;p&gt;The core problem stems from the fundamental difference between &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;class&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;struct&lt;/code&gt; in C#. A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;class&lt;/code&gt; is a reference type, always allocated on the &lt;strong&gt;managed heap&lt;/strong&gt;. When you create an instance of a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;class&lt;/code&gt; using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;new&lt;/code&gt;, memory is allocated on the heap, and a reference to that memory is returned. When that instance is no longer reachable, it becomes garbage, waiting for the GC to collect it &amp;ndash; an operation that can cause noticeable stalls.&lt;/p&gt;

&lt;p&gt;Consider a common scenario: processing temporary query results or calculating scores for nearby entities every frame. If you use a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;class&lt;/code&gt; to represent these temporary data points and store them in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;List&amp;lt;T&amp;gt;&lt;/code&gt;, you&amp;rsquo;re incurring a double hit:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;List&amp;lt;T&amp;gt;&lt;/code&gt; itself is a class&lt;/strong&gt;, though often its internal array can be reused.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Each &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;T&lt;/code&gt; instance (if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;T&lt;/code&gt; is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;class&lt;/code&gt;) added to the list is a separate heap allocation.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let&amp;rsquo;s illustrate with a typical (and problematic) pattern for calculating and processing scores for nearby interactable objects:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// PROBLEM: Class-based data structure&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;InteractableScore&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GameObject&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Score&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Constructor or properties often implicitly lead to heap allocations&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;InteractableScore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GameObject&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;score&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Target&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Score&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;score&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ScoreCalculator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MonoBehaviour&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InteractableScore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_currentScores&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InteractableScore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;_currentScores&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Clear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Clears references, but allocated objects are now garbage&lt;/span&gt;
        
        &lt;span class=&quot;c1&quot;&gt;// Imagine GetNearbyInteractables() yields many results&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;interactable&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetNearbyInteractables&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; 
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;score&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CalculateScore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;interactable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;_currentScores&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;InteractableScore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;interactable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;score&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// !!! EACH 'new' is a GC.Alloc !!!&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;nf&quot;&gt;ProcessScores&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_currentScores&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; 
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IEnumerable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GameObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetNearbyInteractables&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* ... implementation ... */&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GameObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CalculateScore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GameObject&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* ... implementation ... */&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ProcessScores&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InteractableScore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scores&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* ... implementation ... */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Update&lt;/code&gt; loop, if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetNearbyInteractables()&lt;/code&gt; returns 10 objects, you&amp;rsquo;ve just made 10 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;new InteractableScore()&lt;/code&gt; heap allocations every single frame. Over time, this rapid allocation and deallocation will trigger frequent GC cycles, causing noticeable stutter.&lt;/p&gt;

&lt;h3 id=&quot;the-solution-embrace-structs-and-span&quot;&gt;The Solution: Embrace Structs and Span&lt;/h3&gt;

&lt;p&gt;The solution lies in leveraging value types (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;struct&lt;/code&gt;) and efficient memory slicing (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt;). A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;struct&lt;/code&gt; is a value type, meaning its instances are typically allocated directly on the &lt;strong&gt;stack&lt;/strong&gt; (for local variables) or inline within its containing type (if part of an array or another object). When a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;struct&lt;/code&gt; is copied, its entire data is copied, not just a reference. This means no heap allocation for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;struct&lt;/code&gt; itself, and thus, no GC pressure from its creation.&lt;/p&gt;

&lt;p&gt;For temporary collections of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;struct&lt;/code&gt; data, we combine &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;struct&lt;/code&gt; with a pre-allocated array and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt;. An array, even of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;struct&lt;/code&gt;s, is a reference type allocated on the heap &lt;em&gt;once&lt;/em&gt;. By pre-allocating an array large enough to hold your maximum expected temporary data, you perform a single heap allocation at startup. Then, you fill this array with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;struct&lt;/code&gt; instances. Since &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;struct&lt;/code&gt;s are value types, assigning them to array elements does &lt;em&gt;not&lt;/em&gt; create new heap allocations for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;struct&lt;/code&gt; data itself. Finally, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt; provides a lightweight, zero-allocation &amp;ldquo;view&amp;rdquo; into a portion of this array, allowing you to process only the relevant data without copying or allocating new collections.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s the refactored, performance-optimized approach:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// SOLUTION: Struct-based data structure&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;InteractableScoreData&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// It's a struct!&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GameObject&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Score&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ZeroAllocScoreCalculator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MonoBehaviour&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Pre-allocate the buffer ONCE at startup. This is a single heap allocation.&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Choose a size appropriate for your maximum expected interactables.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;InteractableScoreData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_scoreBuffer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;InteractableScoreData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt; 

    &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currentScoreCount&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Tracks how many valid scores we've added to the buffer&lt;/span&gt;
        
        &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;interactable&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetNearbyInteractables&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;currentScoreCount&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_scoreBuffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Prevent out-of-bounds&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;score&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CalculateScore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;interactable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// Assigning a struct to an array element does NOT allocate on the heap!&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;_scoreBuffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;currentScoreCount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;InteractableScoreData&lt;/span&gt; 
                &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; 
                    &lt;span class=&quot;n&quot;&gt;Target&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;interactable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
                    &lt;span class=&quot;n&quot;&gt;Score&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;score&lt;/span&gt; 
                &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;currentScoreCount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;++;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// Use Span&amp;lt;T&amp;gt; to create a zero-allocation view of the valid data in our buffer&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Span&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InteractableScoreData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currentScores&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_scoreBuffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AsSpan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currentScoreCount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        
        &lt;span class=&quot;c1&quot;&gt;// Process the scores using the Span&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;ProcessScores&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;currentScores&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; 
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IEnumerable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GameObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetNearbyInteractables&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* ... implementation ... */&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GameObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CalculateScore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GameObject&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* ... implementation ... */&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;c1&quot;&gt;// Updated to accept Span&amp;lt;T&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ProcessScores&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Span&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InteractableScoreData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scores&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; 
        &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;ref&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scoreData&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scores&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Using 'ref readonly' for even more efficiency&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// Process scoreData directly from the buffer without copying&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$&quot;Target: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scoreData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;, Score: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scoreData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Score&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In this refined code, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_scoreBuffer&lt;/code&gt; is allocated only once when the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MonoBehaviour&lt;/code&gt; starts. In &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Update&lt;/code&gt;, no new heap memory is allocated for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InteractableScoreData&lt;/code&gt; instances. Instead, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;struct&lt;/code&gt; values are directly assigned into pre-existing slots in the array. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt; then provides an incredibly efficient way to iterate over the valid portion of this array without any additional memory allocations.&lt;/p&gt;

&lt;p&gt;This approach not only prevents GC spikes but also significantly improves &lt;strong&gt;cache locality&lt;/strong&gt;. Because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;struct&lt;/code&gt; instances in an array are laid out contiguously in memory, the CPU can process them much faster, leveraging its cache more effectively &amp;ndash; a critical win for data-oriented design.&lt;/p&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;Eliminating insidious &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GC.Alloc&lt;/code&gt; calls is paramount for achieving consistent, high frame rates in Unity. By consciously choosing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;struct&lt;/code&gt; over &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;class&lt;/code&gt; for transient, high-frequency data and combining this with pre-allocated buffers viewed through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt;, you can drastically reduce GC pressure. This isn&amp;rsquo;t just about micro-optimizations; it&amp;rsquo;s about adopting a fundamentally cleaner and faster architectural pattern for your game logic. Start treating memory as a finite resource, and your game&amp;rsquo;s performance will thank you.&lt;/p&gt;
</description>
<category>Other</category>
<guid isPermaLink="true">https://coderlegion.com/21847/is-your-game-choking-on-gc-allocations</guid>
<pubDate>Fri, 03 Jul 2026 21:43:02 +0000</pubDate>
</item>
</channel>
</rss>