Hacker News new | past | comments | ask | show | jobs | submit login

I haven't read the code, but you usually don't let the garbage collector get a chance to do anything with projects where it matters.



In fact, the techniques for C# here would be pretty much the same as for C++ or C: Don't do dynamic allocation in the hot path. And if you must, keep the lifetime short so it gets cleaned up predictably (usually in gen0).

However, for an ancient platform on modern hardware I guess the per-frame budget is plentiful even for an emulator.


Yeah, which is the problem with GC'd languages because it isn't always obvious where allocation will occur.


In what concerns .NET there are Visual Studio plugins that mark exactly that.

D also has something similar as compiler switch.


In what case isn't it obvious? C# makes it quite clear, you allocate to memory on the heap whenever you see the "new" keyword or whenever you see a new closure (because closures are of course just a poor man's objects).


Not necessarily just those things. A foreach loop might have a heap allocation, async/await almost certainly, calling a method with a params[] parameter as well. Everything you call from the BCL might allocate, too and it's not always visible or obvious.

That being said, it is still doable to avoid allocations and the standard library has become much better with not allocating unless really necessary. A lot of the newer things with Span<T> enable zero-allocation usage of certain APIs that before would have allocated.


And even if you use structs with the goal of avoiding allocations, the language doesn't prevent you from accidentally writing code that upcasts them to `object` (eg by calling anything that the struct inherits from `object` and isn't overridden by the struct itself.) This transparently copies the struct to a heap allocation and negates your intent.


This is not entirely true as of C# 7.2. That version of the language adds "ref structs" - which can only be allocated on the stack and cannot be boxed [1].

This requires some care though, as the struct may still be copied needlessly if it is not also marked as `readonly` [2].

[1] - https://blogs.msdn.microsoft.com/mazhou/2018/03/02/c-7-serie... [2] - https://docs.microsoft.com/en-us/dotnet/csharp/write-safe-ef...


Typically, you choose where to optimize after collecting metrics.

The .Net garbage collector is a highly optimized generational garbage collector. Practices like pre-allocating and pooling are discouraged, because most of the time they are premature optimization.

In general, the best way to think about it is to pretend that the garbage collector is a built-in library for pooling and reusing objects.

If, early in your project's lifecycle, you suspect that you'll need to implement your own object pool, just start with stub "Get/Recycle" methods that call new / no-op. You can always swap in a pool later.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: