Well, before I get started on the question, I'd like to say that I do a lot of performance tuning on my software, so I'm very interested in finding out more about your book.
Anyway, I was wondering if you have recommendations on strategies for dealing with applications that create a lot of short persistence objects (when I say "a lot" I mean millions). I used to take pains to try to avoid allowing too many short-lived objects to come into existence because it was my experience that, very soon, the application would start to bog down. So I would code object caches, reusable objects, things like that. Over the last couple of years, I've noticed that Java has gotten much better about this. More than once, I've coded something that previous experience suggested should be an improvement, only to find it barely made a dent in processing times. From my perspective I am generally delighted to see this this because leaving out the special handling makes for cleaner code. But I'd like a better understanding of what's going on.
Is better handling of short-persistence objects a recent improvement to the HotSpot JVM or just something I think I'm seeing? Is the improvement due to enhancements to Java's use of escape analysis?
And finally, most relevant to me (at least), do you have recommendations for strategies to use Java to its best advantage when dealing with this kind of issue?
Thanks. I really am looking forward to seeing your book.
Have you heard of escape analysis? I have probably got the wrong name, but it was introduced in Java6. Objects expected to have a very short lifetime can be created on the stack as a runtime optimisation, and they do not need GC; instead they are simply overwritten next time the memory used is required for a stack frame.
Gary W. Lucas
posted 2 years ago
Thanks. I've heard of escape analysis and suspect it might be the factor related to the performance improvements I've seen. The part that I wonder about is what kind of rules Java uses for deciding it can keep an instance on the stack rather than putting it on the heap. Now some of the rules are going to be JVM dependent, but there must be a certain number of general guidelines that can be applied to strategic code designs... For example, is escape analysis applicable to objects that have an existence outside a single method? If you pass an object into a method, can is still be treated as "escapable"? How about the case where a method returns an object?
I'd like to have a bit more sense of how escape analysis works so that I can use it effectively. So I was wondering if either the authors discussed it in their book or if they might be able to point me in the direction of a good discussion of the subject on the web.
posted 2 years ago
Gary W. Lucas wrote:. . . what kind of rules Java uses for deciding it can keep an instance on the stack rather than putting it on the heap. . . .
Does it say anything in the JLS or the Java® Virtual Machine Specification? I don't remember seeing anything, but I have never looked carefully.
Short lived objects are very common in Java applications, so most GCs have strategies for trying to optimize for this case. All the GCs in HotSpot use a young generation for precisely this purpose. The idea is that most objects live a very short time, so by allocating all newly created objects in a separate area - the young generation - a special GC cycle can be done for only the young generation when it gets full. If the assumption holds, then most object in the young generation will already be dead when the GC happens and there will be very little work for the GC to do.
This only works if the life time of the objects is shorter than the time between GCs. So, if you have problems with short lived objects causing your heap to fill up I think you need to tune your JVM to make sure that the time between the GC pauses is longer than the time you expect your "short persistent objects" to live. The first way to try is to increase the size of the young generation. You can set it this size with -XX:NewSize.
Regarding escape analysis. This is a (JIT) compiler optimization. The goal of the optimization is to find objects that are created but never "escape" outside of the scope that the compiler has knowledge about. Such object don't have to be allocated on the heap as normal objects. Instead the complier can keep track of the their life cycle, normally by simply putting them on the stack instead. This is a nice optimization, but it does not handle all types of short lived objects.