Sunday, September 23, 2007

SQLDeveloper setup trick

by Eduardo Rodrigues

Yes. The title of this post really is SQLDeveloper. I did not write it wrong. But what it has to do with Java? Well, the answer is simple: Oracle SQLDeveloper is a very useful and interesting database tool for developers and is build in Java. It's like an IDE for Oracle DB and has somethings in common with JDeveloper. For those who are now curious, Oracle SQLDeveloper may be downloaded from Oracle Technology Network. I use it and certainly recommend it for developers (not for DBAs).

With all that said, let's go directly to the point...

One of the things SQLDeveloper has in common with JDeveloper is how its setup is done. However, in it's latest versions (1.2.1 was the latest version at the time this post was written), SQLDeveloper has a small setup trick.

As you will notice, SQLDeveloper does not come with an installer program. All you have to do is uncompress the downloaded zip archive and run sqldeveloper.exe located in its root directory. You may choose to download it with a bundled JDK 1.5.0_06 or without it and then set it up to use a more recent JDK (version 6 is already certified). Looking inside the expanded directory tree, you'll find an "<SQLDeveloper_Install_Dir>/SQLDeveloper/bin" subdirectory containing the files "sqldeveloper.conf" and "jdk.conf". The former is the setup starting point and the latter is empty when you download SQLDev without the bundled JDK.

Edit this file and notice the "IncludeConfFile" directives. The first one points to an "ide.conf" file located in "<SQLDeveloper_Install_Dir>/jdev/bin" subdirectory. This file works for SQLDev much like "jdev.conf" does for JDev. Some important things you may setup there is Java Heap maximum size and, specially for Windows users, the keepWorkingSetOnMinimize system property which avoids SQLDev's working memory to be paged out by Windows when you minimize it (believe me, you want this system property set). You may set those like this:

# setting maximum heap to 256 MB
AddVMOption -Xmx256M

#setting keepWorkingSetOnMinimize
AddVMOption -Dsun.awt.keepWorkingSetOnMinimize=true

If you look at the same subdirectory, you'll find another "jdk.conf" file, this time with the following content:

###############################################################
# Oracle IDE JDK Configuration File
# Copyright 2000-2006 Oracle Corporation.
# All Rights Reserved.
###############################################################
#
# Directive SetJavaHome is not required by default,
# except for the base install, since the launcher will
# determine the JAVA_HOME. On Windows it looks
# in ..\..\jdk, on UNIX it first looks in ../../jdk.
# If no JDK is found there, it looks in the PATH.
#
# SetJavaHome C:\Java\jdk1.5.0_04

Because SetJavaHome directive is commented out, this file has pretty much the same effect as the empty one located in "<SQLDeveloper_Install_Dir>/SQLDeveloper/bin" subdirectory. In this case, the application will look for the bundled Java Runtime Engine which should be located in "<SQLDeveloper_Install_Dir>/jdk" subdirectory. And this is the trick. Which of the "jdk.conf" files is the correct one? The answer is: the empty "jdk.conf" in "<SQLDeveloper_Install_Dir>/SQLDeveloper/bin" subdirectory. So, if want or need to specify what JDK should be used to run SQLDeveloper, you must edit this file and add the following:

# tipical setting for Windows
# (you don't need to enclose the path with double quotes)
SetJavaHome C:\Program Files\Java\jdk1.5.0_12

In order to confirm your settings, just open the "About" window and select the "Version" tab:



There you may check what Java is being used and, looking at the "Properties" tab, you may check all other settings.

That's it. Best regards to all!

Sunday, September 2, 2007

JavaOne 2007 - Performance Tips 2 - Finish the finalizers!

by Eduardo Rodrigues

Continuing from my last post about some lessons learned at JavaOne'07 on Java performance since JDK 1.5, there's something we usually do not pay much attention to but which can get us some trouble: object finalizers.

Every time we override the protected void finalize() throws Throwable method, we are implicitly creating a postmortem hook to be called by the Garbage Collector after it finds that the object is unreachable and before it actually reclaims the object's memory space. In general, we override finalize() with the best of the intentions which is to ensure that all necessary disposal of system resources and any other cleanup will be performed before the object is permanently discarded. So why is that an issue?

Well, we all should know that finalize() is an empty method declared in java.lang.Object class, therefore, inherited by any existing Java class. So, when it's overridden, the JVM can't assume the default trivial finalization for the object anymore which means that "fast allocation" won't happen here. In fact, "finalizable" objects have much slower allocation simply because the VM must keep track of all finalize() hooks. Besides, those objects also give much more work to the GC. It takes at least 2 GC cycles (which are also slower) to reclaim a "finalizable" object. The first is the usual one when the GC identifies the object as garbage. The difference is that now it has to enqueue the object on finalization queue. Only during a next cycle GC will dequeue and call the object's finalize() method and, if we're lucky, discard the object and reclaim its space, or else, it may take another cycle just to finally get rid of that object.

If we look closer, we'll notice that putting more pressure on the GC and slowing down both initialization and finalization processes are not the only problems here. Let's take a quick look at the J2SE 5.0 API Javadoc for the Object.finalize() method:

"(...) After the finalize method has been invoked for an object, no further action is taken until the Java virtual machine has again determined that there is no longer any means by which this object can be accessed by any thread that has not yet died, including possible actions by other objects or classes which are ready to be finalized, at which point the object may be discarded. The finalize method is never invoked more than once by a Java virtual machine for any given object. Any exception thrown by the finalize method causes the finalization of this object to be halted (...)"

It is quite clear to me that there's a potential temporary (or even permanent) "memory leak" matter hidden in that piece of Javadoc. Since the JVM is obligated to execute the finalize() method before discarding any object overriding it, in fact, due to the additional GC cycles described above, not only that specific object will be retained longer in the heap but also any other objects that are still reachable from it. In the other hand, even after executing finalize(), the VM will not reclaim an object's space if, by any means, it may still be accessed by any object or class, in any living thread, even if they're also ready to be finalized. Like it isn't enough, if any exception is thrown uncaught during finalize() execution, the finalization of the object is halted and there's a good chance that, in this case, this object will be retained forever as garbage.

At last, the fact that the finalize() method should never be invoked more that once for any given object certainly implies the use of synchronization which is one more performance threatening element.

So, next time you consider writing a finalizer in a class, please, take a second look at it. And if you really have to do that, be really careful with the code you write and try to follow these tips:
  • Use finalizers only as a last resort!

  • Even if you do not explicitly override the finalize() method, library classes you extend may have done it. Look at the example bellow:

    class MyFrame extends JFrame {
    private byte[] buffer = new byte[16*1024*1024];
    (...)
    }

    In JDK 1.5 and earlier, the 16MB buffer will survive, at least, 2 GC cycles before any MyFrame instance is discarded. That's because JFrame library class does declare a finalizer. So, try to split objects in cases like this:

    class MyFrame {
    private JFrame frame;
    private byte[] buffer = new byte[16*1024*1024];
    (...)
    }

  • Even if you're considering to use a finalizer to dispose expensive and scarce resources, keep in mind that, being scarce, it's very likely that they will be exhausted before memory (assuming that memory is usually plentiful). So, in these cases, prefer to pool scarce resources instead.
To be continued...