Back to newsletter 025 contents
A fascinating question on garbage collection in a Weblogic server offered some insight to high performance JMS issues. The messages being fired into the JMS queue were not being collected quickly enough, so memory usage continured increasing until out-of-memory was reached. The questioner had changed his system to use (Weblogic) message paging, which limits the number of messages held in the in-memory JMS queue, queueing further pending messages on the disk. As long as the messages did not have to be processed at maximum speed, the case in this application, then this is an acceptable solution. However, the problem that remained was excessively long garbage collections. To solve this problem, the respondants mostly suggested contacting Weblogic support. But a couple suggested using -Xincgc, the incremental GC option, which breaks GC into smaller chunks to minimize GC pause times. We never found out if this worked.
Another thread posed the interesting problem of needing to access a collection of objects in two ways (in this case by rank order, and by ID). The question was, how should the the array be sorted, and would a linear search provide adequate performance. Suggestions included: using two structures to redundantly store the data, e.g. ArrayList for the sorted access and HashMap for ID access; using an ordered Map such as TreeMap or LinkedHashMap; or simply using one sorted list and using linear search for small collections.
And the last thread that I'll look at this week from JavaRanch posed a similar data structures question. In this case the developer was looking to see if certain fields were present in each of three files containing up to a million records. The only responder to this question, Jim Yingst, gave a thorough analysis of the problem, pointing out the memory problems of searching through that amount of data, suggesting sorting the files and comparing them a fragment at a time, possibly using an external index structure to maintain a sorted order if direct sorting of the files was not possible.
In my first professional programming position I remember watching an external expert and internal expert jousting over some code that was being put together to demonstrate a product. It looked like watching a couple of wizards at work, concocting some esoteric spell. I had that impression once again when reading the JavaGaming discussion about the optimum tile size to use in Java. Here were the animation experts, deciding on how best to draw tiles. It seems that the BLT call is the expensive bit, not the size of the tiles; background buffers BLT'd to screen using offsets are the way to handle changes in perspective; VolatileImage is essential, though not yet fully effective on Linux and not fully supportive of transparent images; and 2D games should use the 3D API, which gives you all you need plus many extra options for free.
Still in with the wizards, this time we have a Sun engineer (another one, apart from the ubiquitous Kesselman) informing how to draw scaled images the fastest. It turns out you may need to enable some forms of hardware scaling, you need to specify -Dsun.java2d.ddscale=true. Using -Dsun.java2d.trace=log helps to see what 2D primitives are being used. But the real gold was that Image.getScaledInstance() has some major performance issues, and you should get an image with Component.createImage() or GraphicsConfiguraton.createCompatibleImage(), and use one of the Graphics.drawImage() calls (which scales on-the-fly) to render your source image to the new image.
Does explicitly setting variables to null help garbage collection? This discussion, with a very good example, showed that there were cases when this was true. In particular, an example was given where Eden was full and an object could theoretically have been reclaimed to make space for a new object, since the new object was being reassigned to the data member variable holding the theoretically reclaimable object. But the reclaim couldn't happen because the data member variable still referenced the reclaimable object, preventing it from GC'd. Consequently, the object was promoted to old generation space, and later required a full mark-sweep GC to reclaim it. The same example with the data member first explicitly nulled was also tested, and showed a huge improvement in speed. The whole discussion is further summarized and extended in this article.
A question that comes up time and again is CMP vs. BMP performance. This time round, the question lead to the most inetersting discussion I've seen. The question, summarized elegantly by the originator:
Clearly BMP means I need to write the persistence layer, but I am confident the system will perform because I write the carefully crafted joining SQL for reading. CMP will reduce our codebase and sounds like Utopia... Can CMP really perform, or are we better staying with BMP supported by various data access patterns?This seems to have elicited some quality answers. The first reply suggested that the issue is more whether to use stateless session beans with JDBC, or entity beans. I agree with that poster that frequently EJBs are used when they are unnecessary, so this alternative should always be looked into. Several subsequent posters suggested that BMP will always be faster if you have optimized it for your own particular application needs. One poster also pointed out that it is not really an either/or situation. Development tools can change a BMP bean to a CMP bean quicker than you can write this line. Finally, the most comprehensive reply from Stephen Kosravi stated: "CMP all alone won't help you, the whole EJB critical path has to be optimized." Kosravi went on to suggest prototyping the two solutions for their particular needs, and also gave a recipe for good CMP performance:
Another poster asked whether JRockit was any good since the idea of a dedicated server-side JVM made sense to him. The only reply suggested that JRockit performed similarly to other JVMs, though the performance was highly dependent on the application. My advice is to try every JVM you have access to with your application. I can guarantee that they will all produce different performance, and that one will be the overall fastest for your application.
The final thread I'll look at asked about the performance gains from clustering the servlet layer and the EJB layer separately. Did the gains from the separately scaled layers outweigh the losses from making all servlet/EJB class remote? Well, there was no answer from anyone who had actually done this, but the sole reply from Joe Hoffman did give a good rationalization to suggest that: "the larger the system is, the more sense it makes to specialize certain VM's to certain tasks. In small systems, this specialization probably doesn't make much sense and is not worth the complexity."
Back to newsletter 025 contents