If last month was characterized by a flood of JDBC information, this month is characterized by J2EE patterns. Although only three articles on patterns made it through to the newsletter (the three that I felt had patterns relevant to performance), there were other patterns articles published. Looking out on the web, I see many sites dedicated to patterns, and the most interesting aspect is that the majority of them provide their examples in Java rather than other languages. This confirms to me that Java is the language of choice for serious software engineering.
To help maintain the patterns emphasis, the tips I've categorized this month are the analysis and design tips. If you look over on the tips page, you'll see three new categorized pages, All analysis & design tips, Design patterns and JDBC design tips.
Apart from those patterns articles, we're getting more articles on garbage collection and heap tuning every month (Kirk notes that the discussion groups are flagging this as important too). And the articles addressing synchronization issues are increasingly becoming ones that address generic shared resource problems. Those of us who have been doing OO programming in multi-user environments recognize these issues as ones we've struggled with for years. Where previously we had to look for information about this in newsgroups, vendor documentation, and obscure journals, now we're getting it all in freely accessible articles with examples in Java. Ah, the power of the web. I certainly feel like it makes me more productive, although I haven't got the metrics to prove it.
I also note that IBM have started a new tips section with short articles (articlets?) on specific Java tips. They aren't all performance specific tips, but this first month four out of five are. It's nice of IBM to work so hard to provide me with material for my website. One of the tips is the first I've listed on JNI (apart from multiple tips to "minimize your JNI calls").
Kirk follows the interesting discussions in the Java performance discussion groups. And we get the added bonus this month of finding out about the flying V, the skills of Eddie the Eagle, and the historic Flying Finn.
And here's my reminder to our Japanese readers that Yukio Andoh's translation will hopefully be available at http://www.hatena.org/JavaPerformanceTuning/ in a while.
Java performance tuning related news.
All the following page references have their tips extracted below.
All the following page references have their tips extracted below.
At the end of the Christmas break, I did something that I hadn't done in quite some time. I watched a FIS K120 meter ski-jumping competition. For the uninitiated, ski jumpers glide down a ramp hurling themselves off the end after reaching speeds in excess of 90km/hr (55 m/hr). They then glide through the air for distances between 100-145 meters (110-160 yards). The skier must then execute a controlled telemark landing. A telemark landing requires that the skier keeps one foot just behind the other. Both knees are bent so that the skier looks as though he is preparing to kneel. A skier's score is the sum of two components, distance and style. Style points are awarded on in-run, take-off, flight, and landing. A proper take-off is the most technically challenging part of the jump. It must be just perfect for the skier to be able to position himself to generate the most lift. To understand just how much lift can be generated, we can look to the exploits of 'Eddie the Eagle' (former member of the UK Ski team). Eddie had no training nor experience when he decided to represent the UK in ski jumping. Lacking the necessary skills, training, coaching and equipment, poor Eddie finished dead last in every contest he competed in. He typically flew about 85 meters, or 30 meters less than most of the other competitors. Since Eddie's speed at the end of the ramp was about the same as the other competitors, the difference in distance can be attributed to his inability to generate lift.
In the traditional ski jumping style, the skies were held perfectly parallel in front of the body. The back and neck were perfectly flat with the skiers nose looking as though it's peering over the end of the skies. The skiers hand are held by his side in a prone position. Hand and arm (and even shoulder) movement, though not desirable, are used to stabilize the flight. In 1985, Jan Boklov introduced a new innovative technique. Ski jumping was never to be the same again.
At the time Matti Nykanen, known as the flying Finn, was the supreme ski jumper. Until he retired in 1988, he was practically unbeatable. In an attempt to gain a performance advantage over Nykanen, Jan Boklov developed a technique which we now call the flying V. To perform the flying V, during flight the skier hold the tips of their skis far apart so the skis form a V. Wind tunnel measurements demonstrated that using the flying V increased lift by as much as 28-percent. Further tests showed that the flight was far more stable. Jan Boklov could now jump farther than the flying Finn. The flights were so long that officials had to lower the starting position on the ramp because Jan (and others) would consistently fly past the K-point on the hill (a point of inflection on the hill after which it becomes increasingly more dangerous to land). But, the Swede still was not able to win because he was heavily penalized for style points. Part of the problem was that Boklov was unable to perform a telemark landing. He was also widely criticized and laughed at for abandoning the traditional jumping style. All of the changed by the 1988-89 season when he finally won the FIS World Cup tittle.
By then, other skiers, looking for that elusive competitive edge, were copying Boklov. By 1993, the flying V was used by every medal winner on the circuit. In the competition that I watched over the Christmas break, every skier used the flying V. To top it off, they were completing the jump with a classic telemark landing. So accolades to Jan Boklov whom, in defying convention, turned the ski jumping world on it's ear. His confidence in his new found technique allowed him to ride out all of the criticism until the establishment caught up with him. Lets see what inspiration and motivation we can find from the performance discussion groups.
Our first stop is at the Java Ranch. I must admit that I'm constantly amazed at how often the ugly duckling topic turns into a beautiful white swan. The most current example has to be a question concerning operators. The poster asked: does the i += k operator produce less byte code than i = i + k? Rather than having his question ignored, the Sheriff stepped in and answered that the byte code although different, was the same size. Now, there was a twist to this. He continued to say that the assembler code was also the same size! The next question is obvious. How did he get to see the assembler code? The Sheriff answered that he had put the code into an infinite loop. He then started the JVM (you must be using the JIT) in a C++ debugger. Since the code was in an infinite loop, the Sheriff claimed that it was easy to see the assembler code. I'm not sure where I might use this technique, but I certainly will put it into my tool box.
The next discussion centered around caching in a J2EE environment. There are several caching strategies that have been built into both application servers and products that function in that environment. In addition, one could write some custom caching as was suggested in the ensuing discussion. The easiest to tackle first is read-only data. That can be read into memory. Session or Entity beans could gain access to the data using a singleton pattern. One other technique that could be used to "pin" the table into memory is to bind it into the app servers JNDI context. For other ideas, check out http://www7.software.ibm.com/vad.nsf/data/document2361?OpenDocument&p=1
One final note. Of the many performance improvements in the JDK 1.4, we can add the method replaceAll() that has been added to String. Since Strings are my favorite performance bug-a-boo, I applaud this addition.
Let's move on to www.javagaming.org as we follow the gamers quest for the perfect gaming experience. Now, I'm not sure why, but a poster was using a DataOutputStream to write out large arrays of float. He was trying to speed up this operation. The advice offered was to look to the new NIO package in the JDK 1.4. In the NIO package, the poster found the FloatBuffer and ByteBuffer classes. By reading in the data in byte chunks into a ByteBuffer, then converting the ByteBuffer into a FloatBuffer, the array of floats could be read in nearly 30 times faster than previously! The ByteBuffer to FloatBuffer conversion doesn't actually do anything other than put a new wrapper object on the underlying byte array. FloatBuffer reads the underlying array as an array of floats, so you can see why this procedure works faster - previously each float had to be read and written one at a time. The new procedure reads and writes the whole array of floats as one big byte array, which is as efficient as it gets.
In another note, there was a design question. The poster was working on a mult-user Java
server. The server would need to execute in the order of five hundred different commands. In
a wise decision, the poster decided not to use 500
Instead he decided to use reflection and then dispatch a message. But as is the case with
every other gamer, he was very concerned with performance. In the chatter, it came out that a
test had been run in both client and server mode. These modes, new to the JDK 1.4,
have a direct effect on garbage collection that can cause significant
performance differences. An early warning to us all that GC tuning is becoming
an increasingly important topic.
The Server Side provided it's usual selection of quality postings and responses. Among these were a number of posts on ECperf. IBM has posted results at www.ecperf.theserverside.com.
In a post that demonstrates that not all performance bottlenecks occur in Java, we find a question regarding the configuration of Oracle. The poster starts by claiming that he is seeing different response times in two apparently identically configured Oracle installations. Although there is a bit of skepticism made about that claim, the response does provide some interesting information regarding Oracle transaction isolation levels and the sizing of TEMP tablespace. It was recommended to use READ_COMMIT as this would result in better response times than those offered by SERIALIZABLE. It was also stated that the sizing of TEMP tablespace should have no effect on performance.
In another posting, a hypothetical question is posed. How should one scale a system that is under increasing demand to perform a set of calculations? As the respondents pointed out, there are two strategies to handle this problem. One is distributed processing, the other is parallel computing. Each come with their own set of benefits and constraints. Once such constraint for distributed computing was that it might cost more to distribute the calculation than to actually perform it. There are other issues with distribution of requests that some hardware manufacture's are trying to address. Most of these rely on a symmetric view of your application. Thus, the suggestion of placing each service on it's own piece of hardware may not offer the best long term solution. Solutions for distributed computing is a fairly open ended topic. It's probably best that one look at their domain to find ways of constraining the solution space.
And that's it for this month's installment of the round-up. See you again next month when I'll discuss why there are so few takers for the ecperf, the J2EE benchmark.
EJB design (Page last updated January 2002, Added 2002-01-25, Author Boris Lublinsky). Tips:
Design Patterns (Page last updated January 2002, Added 2002-01-25, Author Vijay Ramachandran). Tips:
J2EE Design Patterns for the presentation tier (Page last updated January 2002, Added 2002-01-25, Author Sue Spielman). Tips:
Thread programming (Page last updated January 2002, Added 2002-01-25, Author Karthik Rangaraju). Tips:
Multithreading and read-write locks (Page last updated January 2002, Added 2002-01-25, Author Nasir Khan). Tips:
Multithreading and read-write locks, part 2 (Page last updated January 2002, Added 2002-01-25, Author Nasir Khan). Tips:
Expiring cached data (Page last updated January 2001, Added 2002-01-25, Author William Grosso). Tips:
Benchmarking (Page last updated January 2002, Added 2002-01-25, Author Glenn Coates & Carl Barratt). Tips:
Hotspot garbage collection in detail (Page last updated January 2002, Added 2002-01-25, Author Ken Gottry). Tips:
Reference objects (Page last updated January 2002, Added 2002-01-25, Author Jeff Friesen). Tips:
The Garbage Collector (Page last updated January 2002, Added 2002-01-25, Author Phil Vickers). Tips:
Object management (Page last updated January 2002, Added 2002-01-25, Author Mark Bluemel). Tips:
JViewport scrolling performance (Page last updated January 2002, Added 2002-01-25, Author Heather Brailsford). Tips:
Using JNI Get* calls (Page last updated January 2002, Added 2002-01-25, Author Mark Bluemel). Tips:
Typesafe Enumeration gotchas (Page last updated January 2002, Added 2002-01-25, Author Vladimir Roubtsov). Tips:
Servlet 2.3 events (Page last updated January 2002, Added 2002-01-25, Author Budi Kurniawan). Tips:
Design patterns catalog (Page last updated 2001, Added 2002-01-25, Author ?). Tips: