This means you are free today to create objects just to pass in and out of method callsor hold temporary values, a practice which makes your code a whole lot neater, less buggy,and simpler to maintain.

I'll continue my search for the article about the pointer-shift...I found a quote of it, on another website:

Quote

Garbage Collection

The garbage collector has been greatly improved: creating a new object is now an incrediblycheap operation, in most cases equivalent to shifting a pointer in memory. Don't necessarily beafraid of creating many short-lived objects, they will be garbage-collected very efficiently.

Hi, appreciate more people! Σ ♥ = ¾Learn how to award medals... and work your way up the social rankings!

That is disappointing, I thought hotspot would turn the 'new object' code into the 'direct' code. Well at least object creation has gotten better in Java 6. How badly do these bottlenecks affect you, because in all of my games it's the blitting to the screen that takes most of the time.

I wonder why the 1.6 Client VM is so much quicker than the 1.5 equivalent when doing the 'direct' method?

PS: oops, I thought the server VM did all possible native code compilation AND inlining. So inlining must still be done dynamically at runtime by the server VM

However object pooling time is quite consistent and also does not hurt scalability on many CPUs.I am working for a larger company and my job is to tune the stuff other (cheaper *lol*) programmes produce - if you're running on a 32-64CPU machine generating garbage is VERY expensive and HURTS concurrency a lot. However managing memory yourself means ... well you've to take care Have a look at javolution, a nice framework for fast object pooling :-)

I thought the claim was that the garbage collection of small objects is now practically free, as small as shifting a pointer.

Off the top of my head, it is clearly impossible for *object creation* to be that cheap - you have to initialise lots of data in memory (think how much data an object actually contains under the hood if it contains merely a simple float)

Off the top of my head, it is clearly impossible for *object creation* to be that cheap - you have to initialise lots of data in memory (think how much data an object actually contains under the hood if it contains merely a simple float)

Think about it in terms of allocation versus initialization blah^3. Allocation is reserving address space for the object, and initialization is assigning actual values to fields, etc... So, allocation can indeed be as fast as a pointer bump.

I've done this in C++ code where I've written custom allocators for a routine. The routine allocates some millions of nodes over it's relatively short (1 second) execution time. The allocator has a pre-allocated memory pool. When it needs to allocate a node, it simply bumps a pointer. No nodes get deallocated until the very end of the routine, at which point they are all "deallocated" by simply resetting the pointer to the top of the pool. This reduced allocation/deallocation times to just about nil.

You can do something similar in Java by creating an object pool, but those objects are still something that the gc is aware of.

However object pooling time is quite consistent and also does not hurt scalability on many CPUs.

It depends on what your pools look like. If they're MT-safe, that definitely hurts scalability. For example, Java heaps are tuned to be extremely fast for multi-threaded allocations. (They blow the bog-standard C++ allocators out of the water). They can do all sorts of dirty tricks like segmenting different areas of heap address space per thread to reduce contention. There are tricks you can do with object pools too (like creating threadlocal pools, but the cost of a threadlocal lookup isn't zero), but they aren't trivial and do involve other kinds of overhead.

Most people can just forget about allocation and pooling unless they're creating millions of objects / second, or using a class that has heavyweight initialization (e.g. database connections).

I'm fully aware of that, and have run into this in real-world applications, and turned it into a bechmark to show the results with you guys without uploading large packages of code, with at least a dozen dependancies.

Even in realworld cases the results of the changes in architechture were very similar, so please don't think of it as yet-another-benchmark that the JVM isn't handling properly yet.

Hi, appreciate more people! Σ ♥ = ¾Learn how to award medals... and work your way up the social rankings!

I second Riven's comment on the expensive Vec3 construction. I recently reworked some C++ code that used some vector math classes like the Vec3 class. All the Vec3 operators (+-*/) allocated new Vec3 instances (stack allocation). Initially I converted this to 'new Vec3()' in the java code, but the performance was terrible. The algorithm in question was causing lots of very shortlived Vec3 instances to be allocated inside inner loops. I then reworked the code to reuse Vec3 instances as much as possible. This improved performance a lot, but the elegance of the code dropped Unfortunately I can't seem to find my test results...

Off the top of my head, it is clearly impossible for *object creation* to be that cheap - you have to initialise lots of data in memory (think how much data an object actually contains under the hood if it contains merely a simple float)

Think about it in terms of allocation versus initialization blah^3. Allocation is reserving address space for the object, and initialization is assigning actual values to fields, etc... So, allocation can indeed be as fast as a pointer bump.

I've done this in C++ code where I've written custom allocators for a routine. The routine allocates some millions of nodes over it's relatively short (1 second) execution time. The allocator has a pre-allocated memory pool. When it needs to allocate a node, it simply bumps a pointer. No nodes get deallocated until the very end of the routine, at which point they are all "deallocated" by simply resetting the pointer to the top of the pool. This reduced allocation/deallocation times to just about nil.

You can do something similar in Java by creating an object pool, but those objects are still something that the gc is aware of.

Bad description on my part, but what I was trying to do was allude to the fact that a java object that merely contains a float also contains many other bytes imposed by the language. Whereas you have to re-initialize only the float with pooling, with new'ing you have to initialize a bunch of other data.

So, I took "object creation" as used in this discussion to mean "allocation + initialization of required JVM/language/platform data".

Once again, it is probably the case that escape analysis and stack allocation will cure most of this. Due in Java 7 isn't it? I've seen it working in Jet and it pretty much does the trick performance wise.

Escape analysis will help and be a nice addition but it is no panacea. It should easily handle the trivial cases shown in typical microbenchmarks where an object is created, used once, and thrown away all within a single method. For harder cases, for example where the temporary object is used to marshal arguments for a possibly polymorphic method call, it remains to be seen how often escape analysis can handle this for real code in large projects. And of course, if the object has any significant lifespan, for example if the object is part of a larger object, then escape analysis cannot help. It does not allow objects to be inlined into other objects.

The small object overhead is still significant and while escape analysis is a good thing, it only fixes one aspect of a wider problem.

The 1.0 and 1.1 JDKs used a mark-sweep collector, which did compaction on some -- but not all -- collections, meaning that the heap might be fragmented after a garbage collection. Accordingly, memory allocation costs in the 1.0 and 1.1 JVMs were comparable to that in C or C++, where the allocator uses heuristics such as "first-first" or "best-fit" to manage the free heap space. Deallocation costs were also high, since the mark-sweep collector had to sweep the entire heap at every collection. No wonder we were advised to go easy on the allocator.

In HotSpot JVMs (Sun JDK 1.2 and later), things got a lot better -- the Sun JDKs moved to a generational collector. Because a copying collector is used for the young generation, the free space in the heap is always contiguous so that allocation of a new object from the heap can be done through a simple pointer addition, as shown in Listing 1. This makes object allocation in Java applications significantly cheaper than it is in C, a possibility that many developers at first have difficulty imagining. Similarly, because copying collectors do not visit dead objects, a heap with a large number of temporary objects, which is a common situation in Java applications, costs very little to collect; simply trace and copy the live objects to a survivor space and reclaim the entire heap in one fell swoop. No free lists, no block coalescing, no compacting -- just wipe the heap clean and start over. So both allocation and deallocation costs per object went way down in JDK 1.2.

It simply shows there is more to object-creation than just allocation. Even an object with an 'empty' constructor has significant overhead. At least the object-header has to be written (as it's not a struct) which might require fetching the class-id, or something else entirely...

Hi, appreciate more people! Σ ♥ = ¾Learn how to award medals... and work your way up the social rankings!

java-gaming.org is not responsible for the content posted by its members, including references to external websites,
and other references that may or may not have a relation with our primarily
gaming and game production oriented community.
inquiries and complaints can be sent via email to the info‑account of the
company managing the website of java‑gaming.org