Showing posts with label JVM. Show all posts
Showing posts with label JVM. Show all posts

Wednesday, August 25, 2010

System.currentTimeMillis();

I ran across an interesting issue today involving JVM internals, and how they behave differently based on the host OS.

The issue was with the following code snippet:

MyEntity a = new MyEntity();
a.setUid("foo" + System.currentTimeMillis());
a.setName("my entity");
entityService.save(a);

This was part of some object creation code I was using in a unit test, which ran successfully every time on my macbook but was failing on other's windows machines. When I found out the reason behind this, I was definitely surprised.

Believe it or not, it is more or less a known issue that the resolution of currentTimeMillis() on windows machines hovers around 10-15ms (linux and mac have a resolution of around 1ms). This was causing duplicate foreign key violations to occur.

So, as a general rule of thumb, it is a bad idea to rely on currentTimeMillis() to have a millisecond-resolution on windows, especially if you are using it to generate unique things like file names or db IDs. Looks like System.nanoTime() might tick faster.

Here are some links I found on StackOverflow about this:

On Windows, you'll more or less be limited to 10 ms resolution at best. Here's a bit from the Inside Windows NT High Resolution Timers article from TechNet:

Windows NT bases all of its timer support off of one system clock interrupt, which by default runs at a 10 millisecond granularity. This is therefore the resolution of standard Windows timers.

In my experience, using System.currentTimeMillis method gives about 15-16 ms resolution on Windows. Getting better time than the operating system timer will probably require more exotic methods.

Here's the StackOverflow question which helped me solve this issue:
http://stackoverflow.com/questions/351565/system-currenttimemillis-vs-system-nanotime

At the end of the day, I decided it was simpler for my test to use a static synchronized counter variable rather than depending upon currentTimeMillis() for generating my UIDs. Another possible solution could be to use UUID.randomUUID().toString().

Friday, August 14, 2009

Dynamic Classpaths

The JVM's classpath is both one of the more confusing and annoying aspects of Java. Issues always tend to come up when you are trying to make your application easily deployable on client machines, as you inevitably have to jump through some hoops with proper placement of jars, and perhaps some nifty shell scripts to tell the JVM where those jars live.

Because of a combination of the aforementioned reasons and idle curiosity, I set out to see if I could run my application entirely from a single jar, which contained its required library jars within itself. In researching this idea, I found a neat way of dynamically adding jars to your JVM's classpath at run-time.

*N.B. While I consider the code that follows to be 'cool', I don't necessarily consider this to be 'best-practice' for setting classpaths. I prefer putting all of my library jars into a single folder (e.g. './lib'), and bringing the folder onto the classpath using
'-Djava.library.dirs=./lib'.

There are two interesting features of the JVM I discovered that I want to showcase: finding out where you (the code) live in the real world (the file system), and adding jars to the classpath at runtime.

Where do I live?

Similar to Ruby's (and other scripty languages') __FILE__, you can find the actual path to your executing code in Java, as long as you are allowed to by the security / permissions manager. This info is stored in the CodeSource object, which you can get to like thus:

URI clientJarUri = DynamicClasspath.class.getProtectionDomain().getCodeSource().
getLocation().toURI();

The javadoc on the getProtectionDomain() method states: If there is a security manager installed, this method first calls the security manager's checkPermission method with a RuntimePermission("getProtectionDomain") permission to ensure it's ok to get the ProtectionDomain, so keep that in mind when attempting this on secured environments.


Where does my code live?

Once you have the location of your code jar, you can use that to find jars which are relative to it, and tell the JVM about them using the system's URLClassLoader. Classloaders in the JVM are hierarchical, with child instances delegating class requests to their parent if they can't find what they are looking for. The premise here is that we can get at that root classloader, and add to its search path. At first, it seems that the appropriate method to use (addURL()) is hidden to us, but upon further Reflection (ha ha), we have what we need to proceed:

Method addURL = URLClassLoader.class.getDeclaredMethod("addURL", new Class[] {URL.class});
addURL.setAccessible(true);

Now, we can merrily add as many URL references to jars as we desire:

ClassLoader classLoader = ClassLoader.getSystemClassLoader();
for( URL jarUrl : classpathUrlsToAdd ){
addURL.invoke(classLoader, jarUrl);
}

Putting it all together

We now have a simple mechanism for finding out where we are, and adding additional classpath references to the JVM at run-time. This could prove to be useful in certain scenarios, such as deploying apps in a self-contained jar file, as I have done. My build process added all of my library jars at the root of the 'uber-jar', and in the main-class of that jar (my 'bootstrap' class):

  1. Find my location on the file system
  2. Extract all of the jar files from within the currently executing client jar
  3. Add all of those jars to the classloader dynamically
  4. Invoke the actual main class of my app

The only annoying bit was that the bootstrap class doesn't have access to any of my library jars, and therefore I wasn't able to use my favorite library (commons-io) for extracting the jar files from the client jar :-(.