Why use C++ instead of Java?

C

Chris M. Thomasson

Juha Nieminen said:
I assume you are not using gcc? Or you are using your own specialized
allocator?

Ummm, what about something simple like:




C++ version:
___________________________________________________________
#include <cstdlib>


struct foo
{
int m_foo;
};


int
main()
{
for (int i = 0; i < 1000; ++i)
{
std::free(std::malloc(10000000 * sizeof(foo)));
}

return 0;
}
___________________________________________________________




Java version:
___________________________________________________________
public final class tree
{
int m_foo;

public static void main(String[] args) {
for (int i = 0; i < 1000; ++i)
{
tree[] t = new tree[10000000];
}
}
}
___________________________________________________________








Here is the output I get for the C++ version:
___________________________________________________________
$ time ./test

real 0m0.159s
user 0m0.046s
sys 0m0.031s
___________________________________________________________




Here is the output I get for the Java version:
___________________________________________________________
$ time java tree

real 1m36.386s
user 0m0.046s
sys 0m0.031s
___________________________________________________________





Am I doing something wrong in the Java version? Keep in mind that the old
platform I am using right now only has 512mb of ram. C++ seems to do fine,
Java... Not so much. I must be missing something important here!

;^/
 
S

SG

  I assume you are not using gcc? Or you are using your own specialized
allocator?

I used GCC and no special allocator. To be specific:
G++ 4.3.3 versus Sun's HotSpot VM, Java 1.6.0_16
on a i686 Linux box running in 32bit mode.

alloc.cpp:
int main()
{
const long count = 10000000;
int** pp = new int*[count];
for (long i=0; i<count; ++i) {
pp = new int(i);
}
for (long i=count-1; i>=0; --i) {
delete pp;
}
delete[] pp;
}

alloc.java:
class alloc {
static class intref {
public int value;
public intref(int v) { value = v; }
};
public static void main(String[] args) {
int count = 10000000;
System.out.println("h");
intref[] ia = new intref[count];
for (int i=0; i<count; ++i) {
ia = new intref(i);
}
}
}

Cheers!
SG
 
C

Chris M. Thomasson

[...]
Java version:
___________________________________________________________
public final class tree
{
int m_foo;

public static void main(String[] args) {
for (int i = 0; i < 1000; ++i)
{
tree[] t = new tree[10000000];
}
}
}
___________________________________________________________
[...]

Well, this is not correct. I am not a Java user and just realized that this
does not actually create 10,000,000 tree objects. It just creates an array
that can hold references to 10,000,000 tree objects! So, I need to rewrite
the code like:
___________________________________________________________
public final class tree
{
int m_foo;

public static void main(String[] args) {
tree[] t = new tree[10000000];

for (int i = 0; i < 1000; ++i)
{
for (int x = 0; x < 10000000; ++x)
{
t[x] = new tree();
}
}
}
}
___________________________________________________________




Now I get the following output:
___________________________________________________________
$ time java tree
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at tree.main(tree.java:12)

real 0m1.586s
user 0m0.062s
sys 0m0.031s
___________________________________________________________




That's just great!
 
S

SG

Consider that OpenJDK is written in C++. I think that pretty much sums
up the C++ vs Java argument right there.

I don't think it does. It doesn't account for just-im-time compilers.
One could write a C++ compiler in Python, for example. But the
performance of the resulting compiled C++ programs would not be bound
by the language the compiler was written in. The same is true for Java
byte code that is compiled to native machine code by a just-in-time
compiler. The just-in-time compiler approach combines flexibility with
performance.

What's left are all the restrictions the Java language imposes and
which are reflected in the design of the virtual machine. The virtual
machine is forced to do all sorts of checks for null pointers, array
bounds. Allocated objects are under control of a garbage collector.
I'm not familiar with the state of the art of how these things work
and how they affect performance but the simple ref-counted approach
requires some extra code to be executed when objects are allocated,
references are copied, etc. Copying references must also be thread-
safe.

I'm aware of that some of these checks can -- in theory -- be elided
if the just-in-time compiler is smart enough to figure out that it
doesn't need them. For example in this case:

static int[] foo() {
int[] array = new int[256];
for (int i=0; i<256; ++i) {
array = i;
} // ^^^ check needed?
return array;
}

But I would not expect this to make a big difference in general.

Cheers!
SG
 
C

Chris M. Thomasson

[...]
I used GCC and no special allocator. To be specific:
G++ 4.3.3 versus Sun's HotSpot VM, Java 1.6.0_16
on a i686 Linux box running in 32bit mode.
alloc.cpp:
int main()
{
const long count = 10000000;
int** pp = new int*[count];
for (long i=0; i<count; ++i) {
pp = new int(i);
}
for (long i=count-1; i>=0; --i) {
delete pp;
}
delete[] pp;
}



Here is the output I get from the C++ program above:
______________________________________________________________________
$ time ./test

real 0m9.871s
user 0m0.031s
sys 0m0.015s
______________________________________________________________________



alloc.java:
class alloc {
static class intref {
public int value;
public intref(int v) { value = v; }
};
public static void main(String[] args) {
int count = 10000000;
System.out.println("h");
intref[] ia = new intref[count];
for (int i=0; i<count; ++i) {
ia = new intref(i);
}
}
}



Here is the output I get from the Java program above:
______________________________________________________________________
$ time java alloc
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at alloc.main(alloc.java:10)

real 0m1.506s
user 0m0.015s
sys 0m0.062s
______________________________________________________________________




Wow! I guess Java just does not get along with 512mb of ram. Shi% happens
man!

;^o
 
S

SG

Here is the output I get from the C++ program above:
______________________________________________________________________
$ time ./test

real    0m9.871s
user    0m0.031s
sys     0m0.015s
______________________________________________________________________

Here is the output I get from the Java program above:
______________________________________________________________________
$ time java alloc
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at alloc.main(alloc.java:10)

real    0m1.506s
user    0m0.015s
sys     0m0.062s
______________________________________________________________________

Wow! I guess Java just does not get along with 512mb of ram. Shi% happens
man!

For the most part it's a QoI issue (quality of implementation) and not
really related to the programming language. Why should the C++ version
of dynamically allocating many small objects be slower than the Java
version?

What GCC and JVM versions did you use?

Cheers!
SG
 
J

Joshua Maurice

Really people, stop quoting time numbers when running java without the
-server option. Do both -client (default) and -server. -server will
have some additional constant overhead, but otherwise will probably
run much faster for these micro benchmarks.
 
J

James Kanze

On 7 Sep., 08:26, "Chris M. Thomasson" wrote:

[...]
For the most part it's a QoI issue (quality of implementation)
and not really related to the programming language. Why should
the C++ version of dynamically allocating many small objects
be slower than the Java version?

Because C++ implementations use a much older allocator, designed
for C, and for allocating fewer, larger objects. Because of
Java's design, Java programs usually do allocate a lot of small
objects with a short lifetime, enough so that allocator
performance becomes a major issue, and the allocators have been
optimized.

If you want to do a real comparison, try simulating some more
typical use: say allocate a 100 objects up front, then randomly
allocate and free (skipping the free in Java, of course), and
don't forget to free at the end of the C++ as well. You might
want to vary the size of the objects as well. And of course,
you'll definitely want to allocate enough so that the garbage
collector will run in Java---otherwise, Java will show up
unrealistically fast.

Also, of course, you'll want to dimension the test so that it
takes something around 5 minutes, to ensure that you aren't
being mislead by the granularity of your timers, and to make the
start up time of Java negligible (since we want to measure
allocation times, and not start-up time).
 
J

James Kanze

[...]
Why is Java so crappy at memory management? I mean, I am able
to make the program work using C++ and a crappy little region
allocator I whipped up. On the other hand, Java simply runs
out of memory and crashes! WTF is up with that
non-sense!?!?!?!?!

Am I doing something wrong in the Java version????

Without knowing what version of Java you're using, it's hard to
say. Generally speaking, garbage collection trades space for
speed and ease of use; i.e. it requires more memory. In
addition, at least one JVM I used (some time ago---I don't know
what the current situation is) set artificial limits on maximum
memory use, which could be overridden by a command line option.
 
S

SG

Because C++ implementations use a much older allocator,
designed for C, and for allocating fewer, larger objects.
Because of Java's design, Java programs usually do allocate a
lot of small objects with a short lifetime, enough so that
allocator performance becomes a major issue, and the allocators
have been optimized.

You're implying that when designing an allocator you have to make a
trade-off between good performance for few large objects and good
performance for many small objects. I'm not convinced that it *is* a
trade-off. Why can't we have both?

Like you said, Java applications typically allocate more small
objects. So, the allocator's performance plays a more important role
which makes it worthwhile to optimize it. But that's not an argument
against the C++ allocator being a QoI issue. It's just that one cares
less about its performance for many small objects and one doesn't feel
the need to optimize it. ---> QoI issue.
If you want to do a real comparison [...]

Actually, I don't. I don't expect to gain a lot from such a
comparison. As you said, in C and C++ we typically don't rely on the
allocator's performance for many small objects that much. I was merely
questioning Juha's claim. He claimed that allocating many small
objects in C++ is slower than in Java. I could not reproduce it with a
simple test program. So, it looks like his claim was at least too
general.

Cheers!
SG
 
J

Jorgen Grahn

I have a few years of experience with java and c++. I have read that java is
slower than c++ and thats why c++ is often used in eg. graphics applications
instead of java.

But what is it that makes c++ faster and is it really so much faster

I note that that's a different question from the one in the subject
line, "Why use C++ instead of Java".
(considering how fast the hardware has developed in the last few years)?

Faster hardware makes the difference /bigger/ in absolute time, if you
do the math (and if there is such a difference.) But you probably
meant to say "aren't both so fast that it no longer matters?".
I know a lot of current code/libraries are written in c++

Actually, I can't name any except those in Boost. Most are written in
C and usable without change from C++.
but if we neglect
this fact and only look at which language to use for future applications.

You cannot neglect important facts and expect to come up with
something realistic. Those "future applications" will rely on those
"current libraries", or they will be stuck reinventing wheels.

Anyway, what makes the difference to me and makes me ignore Java, is
that I only have to learn the C and C++ libraries once, and then use
them from pretty much any language except Java. With Java it feels
like the libraries probably *are* there, but you have to join the
Church of Java to use them.

/Jorgen
 
B

Bo Persson

SG said:
I don't think it does. It doesn't account for just-im-time
compilers. One could write a C++ compiler in Python, for example.
But the performance of the resulting compiled C++ programs would
not be bound by the language the compiler was written in. The same
is true for Java byte code that is compiled to native machine code
by a just-in-time compiler. The just-in-time compiler approach
combines flexibility with performance.


And then you just need a C++ compiler to make the VM portable?


Bo Persson
 
J

Jonathan Lee

I don't think it does. It doesn't account for just-im-time compilers.

Doesn't it? I haven't used OpenJDK to know if it uses JIT compiler or
not, but if it does it is written in C++. My basic point is just that
between Java source code and machine code is a suite of C++ programs.
How can Java be faster than C++ when it _is_ C++ (interpreting byte
code)?

To me, Java is basically a big C++ program. But that's from looking at
the way it is implemented, not as the language stands theoretically.

--Jonathan
 
J

Jerry Coffin

[ ... various tests using substantial amounts of memory giving
results like: ]
$ time java tree
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at tree.main(tree.java:12)

Ultimately, these show a rather fundamental difference between Java
and C++. Java tends to require more memory to accomplish the same
tasks. In a program that runs for any length of time, you can
generally expect a Java program to consume roughly twice as much
memory as equivalent C++ programs. If there's any real likelihood of
your program approaching what's available, Java probably isn't a very
good choice.
 
S

SG

Doesn't it? I haven't used OpenJDK to know if it uses JIT compiler or
not, but if it does it is written in C++. My basic point is just that
between Java source code and machine code is a suite of C++ programs.
How can Java be faster than C++ when it _is_ C++ (interpreting byte
code)?

As I said: You don't seem to account for JIT compilers. The JIT
compiler I'm talking about is part of the virtual machine that
translates Java byte code directly into native machine code at runtime
when the VM detects some "hot spot" of code that is run quite often.
After this translation of the "hot code fragment" there won't be any
interpretation anymore. Of course, the quality of this compiled native
machine code is not restricted by the language the VM or the JIT
compiler is written in.

So, in a way, "full" compilation of Java programs is just delayed
until runtime whereas a C++ programs are directly compiled to machine
code -- at least for now. This may change in the future, see LLVM.org.

Cheers!
SG
 
I

Ian Collins

SG said:
You're implying that when designing an allocator you have to make a
trade-off between good performance for few large objects and good
performance for many small objects. I'm not convinced that it *is* a
trade-off. Why can't we have both?

Allocator design is full of trade-offs. That's why decent operating
systems provide a choice of allocators.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,150
Latest member
MakersCBDReviews
Top