Easy (but lazy) solution to most of those allocations would be to use LazyCacheStrings and change your code into something like this:
public static LazyCacheStrings<ItemType> ItemTypeStrings = new LazyCacheStrings<ItemType>( (t)=>t.ToString() ); static LazyCacheStrings<System.ValueTuple<float,float>> TitleStrings = new LazyCacheStrings<System.ValueTuple<float,float>>( (kv)=>string.Format("Items {0:0} / {1:0}",kv.Item1,kv.Item2) ); static LazyCacheStrings<System.ValueTuple<ItemType,float>> SectionStrings = new LazyCacheStrings<System.ValueTuple<ItemType,float>>( (kv)=>string.Format("{0} {1:##}",ItemTypeStrings[kv.Item1],kv.Item2) ); void Update () { ItemContainer container = SingletonMB<StationContent>.Instance.GetContainer(); title.text = TitleStrings[ ( container.CapacityUsed , container.Capacity ) ]; sectionLines.RemoveAllLines(); int numContainerItems = container.Items.Count; for( int i=0 ; i<numContainerItems ; i++ ) { ItemStack itemStack = container.Items[i]; sectionLines.Set( ItemTypeStrings[ itemStack.Type ] , SectionStrings[ ( itemStack.Type , itemStack.Amount ) ] ); } }
This should limit worst of this runaway allocations just some seconds after game start (once caches fill up). It's not the best solution but certainly the simplest one to implement.