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

> Switching from C++ to a language without memory safety issues while being just as fast

Does that actually exist? (I mean in the general case, not just a few carefully chosen benchmarks).




Rust is that language.

Some things, namely array indexing and RefCell borrowing, have unavoidable extra runtime overhead in the default safe usage, but it's unlikely that it is significant (often array bounds checks are either essential and thus needed in C++ as well or optimized out by LLVM in Rust, and RefCell usage is generally rare), and you can use unsafe unchecked operations as well.


Yes, they do exist. The safety of Rust comes from the compiler (which takes its time), not from run-time checks. For certain style of code, the JVM is actually faster than C++. You also have to consider, that a lot of things you do in a C++ program to make it safer add up performance costs.


>For certain style of code, the JVM is actually faster than C++.

I find this very hard to believe.


It depends on the nature of the code. Static code is very fast in C++, but dynamic code is less so. Virtual method dispatch in C++ is comparatively slow. Hotspot can eliminate much of the cost by using runtime type information. Using runtime information generally is a way for Hotspot to perform optimizations, a static compiler cannot do, because they would be a bad tradeoff. Heap allocation in the JVM is as fast as stack allocation, this gives another boost vs. heap allocation in C++. And even GCing the youngest generation is basically cost free, as long as you don't have many surviving objects.

I don't claim that Java is always faster than C++, that would be silly and there are plenty of Java programs in the wild which proves that it isn't. But there are quite some tasks at which Java is indeed faster.


In the general case, virtual dispatch has an overhead in both C++ and Java (which btw is only <5 machine instructions), but it's true that Java can sometimes eliminate it with runtime information, which C++ can not use.

However, in my experience, using virtual dispatch is a relatively rare ocurrence in C++ (compared to the vast majority of method calls). On the other hand, on Java, most of _everything else_ is indirect and has overhead: All objects are allocated on the heap, primitives (int) are often objects (Integer) where they ought not to be, all objects have 16 bytes of overhead, etc.

But the JVM will convert those heap allocations to stack allocations! And it will realize those Integers are used as int and remove the overhead! And it will realize you're not using the information on the header of every object!

Perhaps in synthetic benchmarks, but in real programs, where there are an almost infinite amount of code paths, dumb 'data transfer' objects are common and things need to be modularized, the JVM is forced to assume the worst case can happen (even if you as an human can prove that it won't happen) and inhibit those optimizations. And now you have indirect accesses everywhere, memory overhead (=cache trashing) everywhere, the runtime can't vectorize that tight due to Integers, etc.

In fact, I can't think of any domain where there is heavy competition and where high performance is a determining factor where Java has won to C/C++. In browsers, it certainly has not.


> (which btw is only <5 machine instructions)

The number of instructions is much less important than what they are doing. In the case of virtual dispatch, it's doing a memory lookup. If that memory is in cache it could be relatively inexpensive but not guaranteed. However, if you have to hit main memory then things are much slower.

> But the JVM will convert those heap allocations to stack allocations!

I was surprised recently to learn this is not the case. (at least, not with hotspot) The JVM will try and "scalarize" things (pull the fields out of the object which may push them onto the stack) but it won't actually allocate a full object on the stack (OpenJ9 will, but I don't see people using that very often).

It is also somewhat bad at doing the Integer to int conversion. That is mainly because the Integer::valueOf method will break things (EA has a hard time realizing this is a non-escaped value). Simple code like

    Integer a = 1;
    a++;
can screw up the current analysis and end up in heap allocations.

There is current work to try and make these things better, but it hasn't landed yet (AFAIK).

> In fact, I can't think of any domain where there is heavy competition and where high performance is a determining factor where Java has won to C/C++. In browsers, it certainly has not.

I think the realm where the JVM can potentially beat C++ is, funnily, work that requires a lot of memory. The thing that the JVM memory model has going for it is that heap allocations are relatively cheap compared to heap allocations in C++. If you have a ton of tiny short lived object allocations then the JVM will do a great job at managing them for you.


> I think the realm where the JVM can potentially beat C++ is, funnily, work that requires a lot of memory. The thing that the JVM memory model has going for it is that heap allocations are relatively cheap compared to heap allocations in C++. If you have a ton of tiny short lived object allocations then the JVM will do a great job at managing them for you.

Except C++ also has many other options besides malloc() each of these individual objects.


Allocation heavy C++ can be pretty slow. It's also true unoptimizable (pure) virtual methods performing little work have quite a bit overhead that JVM can avoid.

Of course you normally try to avoid writing C++ like that.


Allocation heavy Java is also very slow. But it is much easier to avoid heap allocations (and virtual calls!) in C++/Rust than in Java.


For the time being, I still hope that Valhalla will eventually make it.


The claim is probably that idiomatic code in one case is faster than idiomatic code in the other, not that you can't write C++ code that isn't equally fast.

For example, if you use `std::vector` or `std::unique_ptr` you would be deallocating memory when those go out of scope. The JVM might actually never do that, e.g., if the program terminates before sufficient memory pressure arises.

Writing Rust code that leaks a `std::vector` is trivial, but doing the same in C++ actually requires some skill.


Writing C++ code that leaks a std::vector is absolutely trivial, happens all the time and requires no skill.

  auto* v = new std::vector<char>();


I disagree in that it requires no skill: it requires the user to avoid doing the obvious thing:

    vector<int> foo {...};
and heap allocate a vector on the heap with `new` (without using a smart pointer), and then avoiding your linters warnings about this (e.g. clang-tidy).

If this is common in your place of work, I truly pity you.

Also, trading a call to `free` for a second call to malloc, and a second pointer indirection to the vector elements, isn't a very effective way of improving performance to beat the JVM. The whole idea behind leaking memory is doing less operations, not more :D

In Rust, leaking "the right way" is trivial (mem::forget is safe), but in C++, leaking the stack allocated vector probably requires putting it behind an union or aligned_storage or similar.




Join us for AI Startup School this June 16-17 in San Francisco!

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

Search: