JACOB doesn't release the objects properly - java

I have an eclipse plugin, which connects to a COM component using Jacob. But after I close the plugin entirely, the .exe file stays hanging in Windows processes.
I use ComThread.InitMTA(true) for initialization and make sure that SafeRelease() is called for every COM object I created before closing the app and I call ComThread.Release() at the very end.
Do I leave something undone?

Some further suggestions:
Move the call to ComThread.Release() into a finally block, otherwise the thread will remain attached if an exception is thrown.
Check that you are calling ComThread.InitMTA and ComThread.Release in every thread that uses a COM object. If you forget to do this in a worker thread then that thread will be attached automatically and never detached.
Avoid InitSTA and stick to InitMTA. Even when there is only one thread using COM, I have found InitSTA to be flaky. I don't know how JACOB's internal marshalling mechanism works but I have ended up with "ghost" objects that appear to be valid but do nothing when their methods are invoked.
Fortunately I have never yet needed to modify any code in the JACOB library.

I ran into this issue myself. After messing with initMTA,etc. I found a simple fix - when you start Java add the following to your command line:
-Dcom.jacob.autogc=true
This will cause the ROT class to use a WeakHashMap instead of a HashMap and that solves the problem.
You can also use -Dcom.jacob.debug=true to see lots of informative debug spew and watch the size of the ROT map.

Had the same problem with TD2JIRA converter. Eventually had to patch one of the Jacob files to release the objects. After that all went smooth.
The code in my client logout() method now looks like this:
try {
Class rot = ROT.class;
Method clear = rot.getDeclaredMethod("clearObjects", new Class[]{});
clear.setAccessible(true);
clear.invoke(null, new Object[]{});
} catch( Exception ex ) {
ex.printStackTrace();
}
The ROT class wasn't accessible initially, AFAIR.
Update
The correct way to release resources in Jacob is to call
ComThread.InitSTA(); // or ComThread.InitMTA()
...
ComThread.Release();
Bad thing though is that sometimes it doesn't help. Despite Jacob calls native method release(), the memory (not even Java memory, but JVM process memory) grows uncontrollably.

Related

Java debug without breakpoint

Is it possible to debug a running java process (with Eclipse / IntelliJ) without having a breakpoint? Would be useful to get the state of an object when having a construct like this:
double d = Math.random();
BlockingQueue<String> queue = new LinkedBlockingQueue<String>();
queue.take();
"take()" will block forever, and I'd like to get the value of d with the debugger after take() was called.
I'd like to get the value of d with the debugger after take() was called
A simple solution would be to print the value. Then you don't need the debugger at all. The debugger is useful when changing data due to testing something, inspecting certain objects at runtime etc.
queue.take();
System.out.println(d);
In your case it's not option. One option you can have is to de-compile the jar containing BlockingQueue class, convert them to source files, include it in your project, and set breakpoints inside take() to see the behavior.
One best decompiler is:
http://jd.benow.ca/
using this you can see source of take() function and copy whole class and paste it in your package with name BlockingQueue.java and paste whole source and debug as you wish.
Viewing the state of a thread after an error would be very useful; and while it is more common in some interpreted languages it is sadly lacking in Java. There are however four approaches that come to mind, however bare in mind that the standard approach here in Java is to log important state for later diagnostics.
journal your system, and keep all processing idempotent and deterministic.
attach a debugger after the error; you will not be able to roll back to the point of the exception but you will be able to inspect the current state of the system
add a repl to your server, one that you can telnet into and inspect the system with
Investigate DVR solutions for Java, such as http://chrononsystems.com. They allow rollback of the system to the point of the exception.
Just noticed that there is a pause / suspend button in Eclipse and IntelliJ. This is doing the job.

What is the correct way to use v8::Locker, and why must I use it?

I'm trying to embed v8 in an Android application using NDK.
I have a JNI module that looks something like this (JNI mapping code not shown):
#include <jni.h>
#include <android/log.h>
#include <v8.h>
using namespace v8;
static jlong getMagicNumber() {
HandleScope handle_scope;
Persistent<Context> context = Context::New();
Context::Scope context_scope(context);
Handle<String> source = String::New("40 + 2");
Handle<Script> script = Script::Compile(source);
Handle<Value> result = script->Run();
context.Dispose();
return result->NumberValue();
}
The first time I run getMagicNumber, it correctly runs and returns 42. The second time I try to run it, it crashes.
Specifically, this ASSERT seen in v8's isolate.h fails:
// Returns the isolate inside which the current thread is running.
INLINE(static Isolate* Current()) {
Isolate* isolate = reinterpret_cast<Isolate*>(
Thread::GetExistingThreadLocal(isolate_key_));
ASSERT(isolate != NULL);
return isolate;
}
It sounds a lot like this problem, which suggests using v8::Locker to obtain "exclusive access to the isolate".
By adding a simple Locker l; to the top of getMagicNumber, the crash no longer occurs. Problems that fix themselves that easily tend to break themselves when I'm not paying attention.
I only have the most tenuous understanding of why this fixes my problem, and I'm getting compiler warnings that I'm using v8::Locker in a deprecated fashion. The recommended method is to provide it with a v8::Isolate as an argument to v8::Locker's constructor, but I have no idea how I'm supposed to "obtain" an isolate.
Ultimately: What is the proper way to solve this problem according to the current state of v8, and why?
As I understand it, a V8 isolate is an instance of the V8 runtime, complete with a heap, a garbage collector, and zero or more V8 contexts. Isolates are not thread-safe and must be protected via v8::Locker.
In general, to use V8 you must first create an isolate:
v8::Isolate* isolate = v8::Isolate::New();
Then, to use the isolate from any thread:
v8::Locker locker(isolate);
v8::Isolate::Scope isolateScope(isolate);
At this point the thread owns the isolate and is free to create contexts, execute scripts, etc.
Now, for the benefit of very simple applications, V8 provides a default isolate and relaxes the locking requirement, but you can only use these crutches if you always access V8 from the same thread. My guess is that your application failed because the second call was made from a different thread.
I am just learning V8 now, but I think you need to call:
v8::Locker locker(isolate);
This will create a stack allocated Locker object which will block the Isolate from being used on another thread. When the current function returns this stack object's destructor will be called automatically causing the Isolate to be unlocked.
The you need to call:
v8::Isolate::Scope isolateScope(isolate);
This sets the current thread to run this Isolate. Isolates can only be used on one thread. The Locker enforces this, but the Isolate itself needs to be configured for the current thread. This creates a stack allocated object which specifies which Isolate is associated with the current thread. Just like the Locker, when this variable goes out of scope (when the current function returns) the Scope destructor gets called to un-set the Isolate as the default. I believe this is needed because many of the V8 API calls need a reference to an Isolate, but don't take one as a parameter. Therefore they need one they can access directly (probably through per-thread variables).
All the Isolate::Scope class does is call isolate::Enter() in the constructor and isolate::Exit() in the destructor. Therefore if you want more control you can call Enter()/Exit() yourself.

Kill a stuck thread on a running VM (JBoss Instance) in Java?

A bug in a third party library is causing an infinite loop in a worker thread on a JBoss instance of mine. Do you know of a way to kill this "stuck" thread without restarting the server? We'd like to be able to recover from this until a fix is deployed, preferably without having to restart.
I've seen a few people mention using Thread.interrupt() - if I were to code my own MBean, how would I get a handle to the thread in question in order to interrupt it?
Update: Wasn't able to solve using any of these methods. I did come across another thread about the same issue that had a link to why Thread.stop() is deprecated. Someone else has asked a similar question with similar results. It seems like more sophisticated containers should provide this kind of health mechanism, but I guess their hands are tied w/r/t the JVM.
I had a similar bug (infinite loop) in a 3rd party lib. I ended up applying the fix myself (while waiting for the people from the 3rd party lib to fix their mess) and then I placed the modified .class in my .war, making sure it is loaded before the bogus .class (the bogus one being inside the bogus 3rd party .jar).
It is not nice but it works, see my question here:
Order of class loading from a .war file
What I mean is this: if you have to wait for the people responsible for the 3rd party bugged lib to fix their stuff, you can potentially be waiting a very long time. We couldn't afford that. We needed a fix ASAP. So we ended up applying a patch/hack to their code.
You could for example add a boolean check inside the infinite loop and then forcing the loop to exit when you want the bogus thread to "die".
Note that I haven't used the deprecated Thread stop() since ten years and I really didn't want to use it in the above case.
I suppose the most difficult part is to identify the hanging thread. You provide no info about it, but perhaps you can build some rules around the thread's name or its current stack trace.
If you can identify the thread by its name, I would get all threads in the VM by getting my own thread group with Thread.currentThread().getThreadGroup(), then walk up the thread group hierarchy by calling getParent() on the thread group until it returns null. You now have the top level thread group. You can now fill a preallocated array with all threads using the enumerate(Thread[] list) method on the top level thread group.
If you need the stack traces anyway to identify the thread, you can also use the static utility method Map<Thread,StackTraceElement[]> Thread.getAllStackTraces() to get all threads. Computing the stack traces is however quite expensive, so this might not be the best solution if you don't actually need them.
After identifying the thread you must call the stop() method on it. Interrupting it won't help, unless the implementation of the running code actually evaluates the thread's interrupted flag and behaves as you expect it to. Not that the stop() method is deprecated and that using it may have many funny side effects. You can find more details in the API documentation.
You could use the discouraged myThread.stop() method. But then it is very likely the Thread is still referenced there, so you should use some reflection magic to remove all references to this thread from the components holding it.
How to find the Thread? Use Thread.getThreadGroup() and ThreadGroup.getThreadGroup() to go up to the root ThreadGroup(), and then use the iterate() functions to go through all threads.
Try my jkillthread which tries to do something like this.

Detect Who Created a Thread (w. Eclipse)

How can I find out who created a Thread in Java?
Imagine the following: You use ~30 third party JARs in a complex plugin environment. You start it up, run lots of code, do some calculations and finally call shutdown().
This life-cycle usually works fine, except that on every run some (non-daemonic) threads remain dangling. This would be no problem if every shutdown was the last shutdown, I could simply run System.exit() in that case. However, this cycle may run several times and it's producing more garbage every pass.
So, what should I do? I see the threads in Eclipse's Debug View. I see their stack traces, but they don't contain any hint about their origin. No creator's stack trace, no distinguishable class name, nothing.
Does anyone have an idea how to address this problem?
Okay, I was able to solve (sort of) the problem on my own: I put a breakpoint into
Thread.start()
and manually stepped through each invocation. This way I found out pretty quickly that Class.forName() initialized lot of static code which in return created these mysterious threads.
While I was able to solve my problem I still think the more general task still remains unaddressed.
I religiously name my threads (using Thread(Runnable, String), say), otherwise they end up with a generic and somewhat useless name. Dumping the threads will highlight what's running and (thus) what's created them. This doesn't solve 3rd party thread creation, I appreciate.
EDIT: The JavaSpecialist newsletter addressed this issue recently (Feb 2015) by using a security manager. See here for more details
MORE: A couple of details for using the JavaSpecialist technique: The SecurityManager API includes "checkAccess(newThreadBeingCreated)" that is called on the thread creator's thread. The new thread already has its "name" initialized. So in that method, you have access to both the thread creator's thread, and the new one, and can log / print etc. When I tried this the code being monitored started throwing access protection exceptions; I fixed that by calling it under a AccessController.doPriviledged(new PrivilegedAction() { ... } where the run() method called the code being monitored.
When debuging your Eclipse application, you can stop all thread by clicking org.eclipse.equinox.launcher.Main field in the debug view.
Then from there, for each thread you can see the stack trace and goes up to the thred run method.
Sometimes this can help and sometimes not.
As Brian said, it a good practice to name threads because it's the only way to easily identify "who created them"
Unfortunately it doesn't. Within Eclipse I see all the blocking threads, but their stack traces only reflect their internal state and (apparently) disclose no information about the location of their creation. Also from a look inside the object (using the Variables view) I was unable to elicit any further hints.
For local debugging purposes, one can attach a debugger to a Java application as early as possible.
Set a non-suspending breakpoint at the end of java.lang.Thread#init(java.lang.ThreadGroup, java.lang.Runnable, java.lang.String, long, java.security.AccessControlContext, boolean) that will Evaluate and log the following:
"**" + getName() + "**\n" + Arrays.toString(Thread.currentThread().getStackTrace())
This will out the thread name and how the thread is created (stacktrace) that one can just scan through.

Java keeps lock on files for no apparent reason

Despite closing streams in finally clauses I seem to constantly run into cleaning up problems when using Java. File.delete() fails to delete files, Windows Explorer fails too. Running System.gc() helps sometimes but nothing short of terminating the VM helps consistently and that is not an option.
Does anyone have any other ideas I could try? I use Java 1.6 on Windows XP.
UPDATE: FLAC code sample removed, the code worked if I isolated it.
UPDATE:
More info, this happens in Apache Tomcat, Commons FileUpload is used to upload the file and could be the culprit, also I use Runtime.exec() to execute LAME in a separate process to encode the file, but that seems unlikely to cause this since ProcessExplorer clearly indicates that java.exe has a RW lock on the file and LAME terminates fine.
UPDATE: I am working with the assumption that there is a missing close() or a close() that does not get called somewhere in my code or external library. I just can't find it!
The code you posted looks good - it should not cause the issues you are describing. I understand you posted just a piece of the code you have - can you try extracting just this part to a separate program, run it and see if the issue still happens?
My guess is that there is some other place in the code that does new FileInputStream(path); and does not close the stream properly. You might be just seeing the results here when you try to delete the file.
I assume you're using jFlac. I downloaded jFlac 1.3 and tried your sample code on a flac freshly downloaded from the internet live music archive. For me, it worked. I even monitored it with ProcessExplorer and saw the file handles be opened and then released. Is your test code truly as simple as what you gave us, or is that a simplified version of your code? For me, once close() was called, the handle was released and the file was subsequently successfully deleted.
Try changing your infinite loop to:
File toDelete = new File(path);
if (!toDelete.delete()) {
System.out.println("Could not delete " + path);
System.out.println("Does it exist? " + toDelete.exists());
}
or if you want to keep looping, then put a 1 second sleep between attempts to delete the file. I tried this with JDK6 on WinXP Pro.
Don't forget to put a try/catch around your close() and log errors if the close throws an exception.
Make sure you have your close calls in the finally block not in the try block. If there is no try/finally because the method throws the exception then add a try/finally and put the close in there.
Look at the Windows Task Manager. For the Processes add the "Handles" column (under the View menu). Watch to see if the handles keep going up without ever dropping.
Use a profiler to see if you have Stream/Reader/Writer objects around that you do not think you should have.
EDIT:
Thanks for posting the code... off to see it. One thing - your close methods are not both guaranteed to execute - the first close might throw and then the second won't run.
EDIT 2:
final WavWriter wavWriter = new WavWriter(os);
LACDecoder decoder = new FLACDecoder(is);
The above two lines will cause the strams to be kept in instance variables presumably. As a test see if you can set the stream references to null after the decoder.decode() call (make a decoder.cleanup() method perhaps). See if holding onto the closed streams is causing a problem.
Also, do you do any wrapping of the streams passed into the above constructors? If so you might have to close the streams via the wrappers.
Your code sample should definitely work. In fact I ran your it on Java 1.6/Vista with jflac 1.3 and the source file is deleted, without any looping.
I'm guessing in your case another process is keeping the file open, perhaps a desktop search indexer or an antivirus. You can procexp to find which process is actually holding onto the file.
Isn't that an empty while loop?
you have:
try
{
...code
}
finally
{
}
while (something);
put some whitespace in there, and you actually have:
try
{
...code
}
finally
{
}
while (something)
;
your while loop isn't related to your try/finally. if your original try statement fails and the file isn't created, that while loop will never complete, because the try/finally will never execute a second time.
did you intend to make that a do{ all your code } while (your while statement)?
because that isn't what you have there.
EDIT to clarify:
my suggestion would be to change your while loop to have more info of why it can't delete:
while (!file.delete())
{
if (!file.exists())
break; // the file doesn't even exist, of course delete will fail
if (!file.canRead())
break; // the file isn't readable, delete will fail
if (!file.canWrite())
break; // the file isn't writable, delete will fail
}
because if delete fails once, its just going to fail over and over and over, of course its going to hang there. you aren't changing the state of the file in the loop.
Now that you've added other info, like Tomcat, etc, is this a permissions issue? are you trying to write to a file that the user tomcat is running as (nobody?) vm can't create? or delete a file that the tomcat process can't delete?
If process explorer/etc say java has a lock on the file, then something still has an open stream using it. someone might have not properly called close() on whatever streams are writing to the file?
If you are out of clues and ideas: In cygwin, cd to your javaroot and run something like:
find . -name '*.java' -print0 | xargs -0 grep "new.*new.*putStream"
It might provide a few suspects...
Another thing to try since you're using Tomcat-- in your Context Descriptor (typically Tomcat/conf/Catalina/localhost/your-context.xml), you can set
antiResourceLocking=true, which is designed to "avoid resource locking on Windows". The default for this (if you don't specify) is false. Worth a try.

Categories