Java on Big Memory Machines

J

Joseph Dionne

Harald said:
With HotSpot, Java is a compiled language and in may daily
use I figured it matches up easily with your "compiled"
language of choice.




The OP (thats me) does huge data structures with Java already,
admittedly not byte arrays of course. And the OP is very happy
that the GC cleans up after him, sometimes even faster and
certainly with less hassle than free() does.

Harald.


Mr. Kirsch, I believe you misunderstood the dynamic of my comments. The
nature of Java is efficiency on wide ranging platforms. By
definition, your servers are unique, and as such require a unique
solution for your application. Me, I would create my own home rolled
large array classes in JNI, and viola, Java's limit is gone.

But, as for using free(), the most widely abused function in c, it is
not the c language "fault" because a developer cannot manage memory. I
personally do not like garbage collectors, simply because I do not write
garbage. My j.o.b. is to manage memory, and other resources, and not
require some language developer compensate for my failures.

Sorry is that sounds harsh.

Joseph
 
D

Dimitri Maziuk

Betty sez:
[ ojbect reachability ]
Maybe I don't understand what you mean.
I have seen a couple of books that give examples where an object is
not reachable. How about this.

String[] a = new String[] = {"you", "make", "me", "feel", "so",
"young...",};
a = null;
// at this point there is no way to print out the
// original object containg the 6 words.

If a language is not garbage-collected, an unreachable
object is an error called "memory leak". I.e.

delete [] a;
a = null;

-- without "delete a" "a = null" is a memory leak.

GC eliminates memory leaks[0], but it does that at the expense
of e.g. maintaining extra members in each object for reference
counting and/or code to iterate through objects and determine
their reachability, etc. -- dep. on GC scheme.

Once GC decides that "a" is not reachable it does the equivalent
of "delete a".

Hence my comment: the only way GC can be faster/more efficient
than explicit "delete a" is if it runs in negative time and
uses negative amount of memory. It eliminates a common class
of programing errors, yes, but claiming that it's more efficient
at the same time is like claiming you can eat your cake and have
it, too.

[0] though it does nothing for other resource leaks, server-side
database cursors being the most common example.

Dima
 
A

Adam P. Jenkins

Dimitri said:
If a language is not garbage-collected, an unreachable
object is an error called "memory leak". I.e.

delete [] a;
a = null;

-- without "delete a" "a = null" is a memory leak.

GC eliminates memory leaks[0],

Actually GC doesn't eliminate memory leaks. The programmer no longer
needs to explicitly free objects before they become unreachable, but the
programmer is still responsible for making sure that an object *becomes*
unreachable when it's no longer needed. I've seen plenty of memory
leaks in large Java applications due to forgotten references to objects.
but it does that at the expense
of e.g. maintaining extra members in each object for reference
counting and/or code to iterate through objects and determine
their reachability, etc. -- dep. on GC scheme.

Once GC decides that "a" is not reachable it does the equivalent
of "delete a".

Hence my comment: the only way GC can be faster/more efficient
than explicit "delete a" is if it runs in negative time and
uses negative amount of memory. It eliminates a common class
of programing errors, yes, but claiming that it's more efficient
at the same time is like claiming you can eat your cake and have
it, too.

You seem to be claiming that in principle GC can't be faster than
explicit memory management, but there are a number of things wrong with
your argument.

Your argument seems to boil down to the claim that similar programs, one
using GC and the other explicit memory management, will need to perform
the same number of allocations and deallocations. Furthermore you seem
to be using the implicit premise that each allocation and deallocation
will take some fixed constant amount of time, regardless of whether GC
or explicit memory management is used. Therefore, at best GC could only
be as fast as explicit memory management.

I think one flaw in your argument is that you're assuming that malloc()
and free() run in constant time. If that were true, then it would be
hard to see how GC could be *much* more efficient than malloc/free. It
would still be possible for a particular GC to be more efficient than a
particular malloc/free implementation by some constant factor, but
that's it, since as you say the same number of allocations and
deallocations would still need to take place.

However, in fact malloc and free don't run in constant time. Behind the
scenes they need to maintain some sort of data structures that keep
track of memory blocks of different sizes, and try to allocate memory to
minimize fragmentation. The result is that malloc and free will take at
least O(log n) time, where n is the number of blocks being tracked. One
advantage some GC schemes have over malloc/free is that they can
defragment memory by moving allocated blocks around and coalescing free
blocks, thereby reducing the total number of blocks, and therefore speed
up allocations. Another advantage of defragmenting memory is it can be
used to reduce memory cache misses.

Another advantage for short running programs is that since GC can
postpone deallocations until it actually needs the memory, if the
program exits before needing more memory, those deallocations may not
even need to occur.

These are all theoretical advantages, but my point is to dispute your
claim that in principal GC can't be faster than explicit memory
management. In fact I've read several studies which show that GC is
often competitive or faster than manual memory managers with regard to
execution speed. However GC typically results in higher memory
requirements than explicit memory management, and less deterministic
execution speeds because a GC can occur at any time. So for certain
applications manual memory management may be necessary, but when
minimizing memory usage or deterministic execution speed aren't
requirements, then manual memory management seems like a waste of effort.

If you're interested in research on this subject, google for "automatic
explicit memory management comparison".

Adam
 
M

Matthias Buelow

Adam P. Jenkins said:
I think one flaw in your argument is that you're assuming that
malloc() and free() run in constant time. If that were true, then it
would be hard to see how GC could be *much* more efficient than
malloc/free. It would still be possible for a particular GC to be
more efficient than a particular malloc/free implementation by some
constant factor, but that's it, since as you say the same number of
allocations and deallocations would still need to take place.

In addition to malloc() and friends having logarithmic time, the same
number of allocations and deallocations do _not_ have to take place.
"Garbage collection" is a misnomer. In fact, what normally gets
collected isn't garbage, but live memory. Depending on the algorithm
being used, the "garbage" is often ignored and not touched at all. If
you have a high garbage-generating rate, and, at GC time, only a small
live set, then "collecting" only the live memory (by tracing
references from a root set) will be a lot faster than having to
deallocate the "garbage", in an explicit management scenario. The
well known semispace "broken heart" copying algorithm works that way.
I don't know what algorithm the java vm is using.

mkb.
 
D

Dimitri Maziuk

Adam P. Jenkins sez:
....
I think one flaw in your argument is that you're assuming that malloc()
and free() run in constant time.

Not quite: I'm assuming that JVM calls the same malloc(), at least
when it needs to grow its heap.

Sure, in a pathological case VM can pre-allocate the whole -Xmx,
lock it memory so it's never swapped out, and never actually deallocate
memory. Add the code that creates large number of very short-lived
objects, and you get much better performance from GC'ed VM.

Consider another pathological case: jvm starts with its default Xms and
runs out of heap space. GC kicks in, cannot free enough memory, JVM has
to grow its heap. Guess who it calls? -- malloc(). Which runs in log(n)
time, defragments free memory, starts swapping pages in and out, etc.
You get log(n) time of malloc(), *plus* the time taken by GC.

The problem with carefully constructed corner cases is that it's easy
to come with ones that clearly show that in theory, pigs fly.
These are all theoretical advantages, but my point is to dispute your
claim that in principal GC can't be faster than explicit memory
management.

I don't doubt that GC *can* be faster. I doubt that *properly written*
code that does its own memory management will be slower than GC.

Dima
 
L

Lee Fesperman

Dimitri said:
Adam P. Jenkins sez:
...

Not quite: I'm assuming that JVM calls the same malloc(), at least
when it needs to grow its heap.

I doubt that the JVM uses malloc(), which is part of the C library. I would assume it
uses the lower-level operating system call to get a chunk of memory ... the same one
that malloc uses to get its chunks.
Sure, in a pathological case VM can pre-allocate the whole -Xmx,
lock it memory so it's never swapped out, and never actually deallocate
memory. Add the code that creates large number of very short-lived
objects, and you get much better performance from GC'ed VM.

Consider another pathological case: jvm starts with its default Xms and
runs out of heap space. GC kicks in, cannot free enough memory, JVM has
to grow its heap. Guess who it calls? -- malloc(). Which runs in log(n)
time, defragments free memory, starts swapping pages in and out, etc.
You get log(n) time of malloc(), *plus* the time taken by GC.

Bad assumption.
The problem with carefully constructed corner cases is that it's easy
to come with ones that clearly show that in theory, pigs fly.


I don't doubt that GC *can* be faster. I doubt that *properly written*
code that does its own memory management will be slower than GC.

In general, the JVM allocates memory by simply incrementing a pointer, much faster than
malloc(). GC frees a bunch of allocations at once at considerably less cost than a bunch
of calls to free(). The bookkeeping is completely different under GC. In some cases, it
only takes a few instructions to 'free' a large block of allocations. No 'properly
written' sequence of mallocs and frees can outdo that.
 
L

Lee Fesperman

Lee said:
I doubt that the JVM uses malloc(), which is part of the C library. I would assume it
uses the lower-level operating system call to get a chunk of memory ... the same one
that malloc uses to get its chunks.

Excuse for responding to myself, but I couldn't remember (off the top of my head) the
function that malloc() uses and the JVM undoubtedly uses to get chunks of memory. It's
sbrk().
 
M

Mark Thornton

Lee said:
Excuse for responding to myself, but I couldn't remember (off the top of my head) the
function that malloc() uses and the JVM undoubtedly uses to get chunks of memory. It's
sbrk().

Very unlikely in the case of Windows implementations. The Sun JVM
reserves enough address space for the maximum requested heap, and then
commits part of this space as required. It apparently gains some
efficiency from ensuring that the heap is contiguous.

Mark Thornton
 
L

Lee Fesperman

Mark said:
Very unlikely in the case of Windows implementations. The Sun JVM
reserves enough address space for the maximum requested heap, and then
commits part of this space as required. It apparently gains some
efficiency from ensuring that the heap is contiguous.

So, what is likely for Windows? I doubt it is malloc(). However, the real issue is that
the JVM will grab large chunks making the overhead of those allocations unimportant.
 
D

Dimitri Maziuk

Mark Thornton sez:
I don't know exactly what memory allocation mechanism is used by a given
JVM; I know at least some of them are written in C and thus may well use
C library functions.

It's a moot point anyway: user program does not have to call malloc()
either. It can, at least in theory, use the very same memory allocation
mechanism JVM uses. You can roll your own malloc() and free() (and their
C++ cousins).
Very unlikely in the case of Windows implementations. The Sun JVM
reserves enough address space for the maximum requested heap, and then
commits part of this space as required. It apparently gains some
efficiency from ensuring that the heap is contiguous.

Moreover, linux manpage claims brk is not part of POSIX.1. If that's
true, sbrk() is not necessarily available on *any* POSIX.1 system (IRL
most of them would have it, inherited from BSD).

Dima
 

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
474,431
Messages
2,571,677
Members
48,796
Latest member
Greg L.

Latest Threads

Top