Hacker News new | ask | show | jobs
by Cojen 2028 days ago
I've found that coding in a "C-like style" offers great performance too. Are there any languages that target the JVM and are designed for higher speed? If it enforced the "C-like style" at the language level, perhaps it would be easier to follow?

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.

2 comments

I find Java itself works quite well for this. Especially newer Java versions with functional interfaces. You keep your data in data centric classes (e.g. something akin to struct-of-arrays in C) and have some functional interfaces to access this data, the only place where you loop over it, maybe in batches if it's really large (test it though, up to 10s or 100s of millions of elements is still fast to loop through in memory). Then you got some algorithm centric classes that you can plug into these interfaces. And finally, after reducing the data you may have some classic objects, e.g. to represent results.

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.

> Are there any languages that target the JVM and are designed for higher speed?

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.

In Java, every object stored on heap (and they can't be stored on stack) has a JVM-induced space overhead. Also, the allocator is free to spread the objects across the heap in a chaotic manner, which will make for less than optimal utilization of cache lines.
That's... not how JVMs work.

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.