Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

Since the introduction of JLink (maybe a bit later) it is possible to put jar libraries inside the directory-structure of packages. If this package is installed in one of the places Mathematica searches, the jar libraries are automatically found by JLink.

The problem is that under 64 bit Windows XP, after loading JLink these files are locked and cannot be removed from within Mathematica, although none of the jars are really used, but only added to the class-path of Java.

Let me give a short example: Place a Test folder with Java subfolder inside your $UserAddOnsDirectory and copy any jar file into the Java folder. This looks like

Test/
└── Java
    └── blub.jar

When you now start a fresh Kernel and load <<JLink` you can verify by looking at JavaClassPath[], that this directory and the jar was indeed added to the class-path. When you try to remove the complete folder, you get (a misleading) error message

DeleteDirectory[path, DeleteContents -> True]

(*
    DeleteDirectory::dirne: Directory D:\Documents and Settings\mscheibe\
    Application Data\Mathematica\Applications\Test not empty. >>
*)

After Quit-ing the kernel, calling UninstallJava[] or JLink`QuitJava[] the directory can be removed. This behavior does not occur in Linux or on MacOSX and I could only test it on Windows XP 64 bit.

Question: Why, if the jar-path is only appended to the class-path, does JLink lock the files as they where opened for reading? Why does this happen on Windows only? Is there anyone, who has a deeper insight into JLink who can suggest a better solution that calling JLink`QuitJava[]; Pause[2]; inside my module when I want to remove a jar-file found by Mathematica.

Remark 1: This behavior is not restricted to automatically found jars. When you use java-code by manually adding a jar with AddToClassPath[path] the similar thing happens.

Remark 2: I forgot to mention, that JLink`QuitJava[] does not really quit java like Quit would kill the kernel. Meaning, I call this and without doing anything else I can still call my functions inside the jars. This seems to suggest, that QuitJava[] kills the class-loader instance Leonid is mentioning which locks the files. But a call to e.g. JavaNew seems to set up everything correct again.

share|improve this question

1 Answer 1

up vote 7 down vote accepted

I also encountered this problem. Not an authoritative answer, but here is one blind guess to what is happening. JLink has its own classloader, JLinkClassLoader.java, which calls another one, JLinkClassLoaderHelper.java. The latter is a sub-class of URLClassLoader.java. Both are used in the class JLinkSystemClassLoader.java. The second part of this story is that there is an unresolved bug in the JVM related to URLClassLoader.java class, which locks jars, on Windows only. It has been discussed on SO here. The problem seems to be Windows-specific. What I don't know is at what time this happens, and why this affects jars that weren't even used. If this is at all a right guess, this can probably be traced by using a debugger.

share|improve this answer
    
+1 This seems to explain, why you can break the lock with QuitJava. Does this mean that, when I have a few million jars in my search-path, JLink` opens and maybe loads every jar at startup instead of adding it to the search path? Does java has to preload jars or could it just start loading, when a symbol cannot be resolved? –  halirutan Feb 7 '12 at 10:34
    
@halirutan To answer this, I'd need to have a deeper understanding of the dynamics of class loading in JLink. I think however, that if/when this becomes a real problem, one can try to get a hold on the specific instance of URLClassloader (well, its J/Link subclass) created by JLink. In the JDK7, a new method close has been added to it, so I suppose it can be used explicitly from JLink/Mathematica, when you are done loading classes. Then, if you need to load more, you create a new instance. Something like that may work, but for that a full understanding of the process may be needed. –  Leonid Shifrin Feb 7 '12 at 10:59
    
@halirutan From a cursory look at it, here is a work-around I'd suggest: 1. Subclass the JLinkClassloader class, making a field helper (of type JLinkClassLoaderHelper) public (it is protected in JLinkClassloader, which creates a singleton). 2. Work directly with the KernelLink.java class, which has a method setClassLoader: create an instance of KernelLink, and then set as the classloader the subclass I mentioned. 3. When needed, access the field helper of this subclass, and call close() on it. Then replace it with a new instance of the helper. No idea if this works though. –  Leonid Shifrin Feb 7 '12 at 11:09
    
@halirutan Here is a link which may be of interest: reference.wolfram.com/legacy/v7/JLink/ref/java/com/wolfram/… –  Leonid Shifrin Feb 7 '12 at 11:09

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.