> And some of it doesn't even require unsafe code. In many cases C#'s compiler optimizes away the array bounds checks.
Quite true.
> For some specific kinds of applications it's definitely pure overhead...
I started coding back in the early 90's, so I have a lots of experience with manual memory management. Nowadays I use mostly GC enabled ones (native or managed).
There some special cases like real time systems, or very complex games where GC might hurt, but I think the main issue is that many developers lack the knowledge to use GC enabled languages properly.
You need to organize the data structures and algorithms in a GC friendly way, which is different than doing manual memory management. Allocating memory faster than the GC can handle it, or getting 1GB just because, won't make your application behave nicely.
> Lower-level languages are great for when there's a lot to be gained by carefully managing CPU cycles ...
On the other hand, the optimizer is sometimes limited in what it can do, because of those low level constructs. C pointer aliasing is a good example.
For me, the best solution would be a kind of hybrid approach, similar to what .NET already does, or the Lisp environments also do.
You make use of a VM like environment (with JIT) for development purposes, but additionally have the option to aot the code to native for redistribution.
So lets say like ngen, but where all the non used stuff is removed.
But good developers should also be able to drop down to Assembly, C, C++, if the application really requires it.