Of course at this point the usual answer is just use Rust, but is there a language that meets in the middle? Sometimes I just want the GC to do the work and I'm okay with that.
edit, to give you an example. Let's say you have double precision X/Y coordinates. Put that into a class with two double arrays for X and Y. In order to e.g. run an Euclidean distance computation against it, provide a (double, double) -> double interface against it. Then you have either an Euclidean distance class providing that function or just an inline lambda that you can plug into that interface, giving you a distance array. Let's now say you just want to have a list of 10 closes points - instead of sorting you're fastest to brute force it. Only after you reduced it down to the 10 points, you put them into Point objects because there's probably a consumer expecting it that way.
Yes: Java
Performant Java looks mostly like C, just with no manual malloc() calls.
Sure you could write Java in a J2EE way but.. that not a good choice.
All modern VMs (not just limited to Java here!) apply two key optimizations. The first is escape analysis, which checks if references to objects will escape the current function boundary. If not, the objects will be stored on the stack instead of the heap. The second is generational GC, where memory allocation looks like this:
void *new_ptr = heap_mem;
heap_mem += alloc_size;
if (heap_mem >= max_size)
outlined_function_to_get_larger_blocks_of_memory();
It's actually likely to be a tighter allocator than C/C++'s malloc, since there's no mucking about with freelists.Assuming those libraries do not do allocations of their own negating all the efforts.
It really can't. Quite the opposite. Writing C-like Java is already doomed from the start. Java is faster than C when it comes to OOP. Unless you product is a highly complex OOP nightmare, C will always beat Java to the curb.
GC is not free. The problem with GC is that you pay asynchronously, while allocations are essentially free. But this asynchronous cost is very very hard to measure and to control. Java does not offer the mechanism C/C++ offer for native resource management. It also doesn't do complex optimizations, most notably vectorization. Number crunching performance will always suck in Java. Even if they add all the optimizations in the world, the simple fact remains: Java as a language simply does not allow you to express code in a performant way. That leave the compiler at a double disadvantage. It needs to essentially "convert Java to C++ and guess the most performant interpretation" (we are decades away from this), and it needs to do that within milliseconds (because its a JIT).
It just makes no sense to talk about this. Use Java for the 99% of your product that is not a hotpath, use C for the remaining 1% where you need pure performance. Simple as that.