If you are running code that makes calls to a native library in Java, what is the usual way of freeing memory allocated by these libraries when the memory allocation should last for the lifetime of the object? In C++, I would use destructors, but Java never really had those and has them even less now.
The specific case I'm most interested in is JOCL, where I have an object that wraps a compiled OpenCL kernel and all of the arguments thereto that are always the same. Structures representing the compiled kernel and the arguments are all allocated on the library side, and JOCL provides a method clReleaseMemObject that you call to decrement a reference counter indicating when the object should be deleted (note that this is a bit different from directly freeing the memory, but I don't think substantially so in this case).
I presume that if the object is still around when the program terminates, everything is cleaned up by the OS, but I'm not so sure about about objects created in a thread. So:
If you want the native memory deallocated when the object is garbage collected, is there a proper place to call the method that releases this memory?
If the object is one that will last for the duration of a thread, is there a proper place to make this call, or is this even necessary?
What you can do is use a Cleaner. This is a more official API in Java 9 but is available in Java 1.4+.
Essentially you give it a Runnable to execute when the resource is cleaned up.
One advantage of using a Cleaner is you can call it to clean up deterministically, but if you forget or fail to do so, the GC will call it after it runs.
There isn't a safe way to clean up an object when a thread dies as the Thread object can live for the life of the program even if dead. A simpler approach is to clean up as you know it is not needed or after the GC determines it is not required.
Another approach is to use a reference queue and a background thread. It's not as elegant but works across Java 8 and later versions.
Related
I have a situation where I want to instrument Java code to add function calls, those function I add calls to might affect the objects status in the system thus changing the state of the program. I am looking for a way to insert those calls but leave the program status unchanged.
I am looking for a method to store the status (Image?) of the heap and come back to it later, I mean at the end of my instrumentation code. I tried tuckling it with an idea of copying the current JVM, maybe execute the instrumented code inside it (with the exact state of the program) and come back to the original JVM when the instrumentation is done. I couldn't find a documentation on such scenario so I am wondering if there is a better approach to it.
The state of Java program is not only the Heap. It also includes running threads, loaded classes, constant pools, caches and many other VM structures.
Saving state of a Java program is roughly the same as saving state of an arbitrary process in OS. fork is probably the closest way to achieve this, but it's still not an easy solution.
I have a small java application running a set of computational heavy tasks. For processing the tasks, I use an external library which does most of the computation via native methods and some C code. Unfortunately, after solving one task, the library suffers from heavy memory leaks and can therefore only solve one task per application execution.
The memory problem is known to the coders from the library, but not fixed yet and maybe never will (it has something to do with the java garbage collector not properly working with the native inferface). Since there is no alternative for this particular library, I am looking for options to solve the tasks by sequentially application executions.
Currently, I have a bash wrapper script, which gets a list of tasks that should be executed and for each task the script calls the application with just this single task to execute.
Since tasks often need the results from previous tasks, this involves serializing and deserializing execution results to files. This does not seem to be good practice to me, also because the user has basically no way to interact with the program control flow.
Does anybody have an idea how I can to this sequential task execution inside one single java application? I guess this would involve starting a new JVM for each task exection, hopefully only transferring the task result and not the memory leaks from the new JVM to my application.
Edit providing further information:
Changing the root of the problem: Unfortunately, the library is not open source and I have neither access to the native methods nor to the java interface api.
New processes / JVMs: Is that the same in this context? I have not much experience with the java process api or starting new JVMs. My assumption is that this would involve starting a separate java program with its own main function using ProcessBuilder.start()?
Exchange of data: It is only a couple of kilobytes so performance is not an issue. Still, a solution without files would be preferable, but if I understand correctly memory mapped files also use local files. Sockets on the other hand do sound promising.
Funnily enough, I've faced the same issue. By definition, you need to accept nothing will be best practice or nice faced with having to use a faulty library you must use but cannot upgrade.
The solution we came up with was to isolate calls to the library in it's own process. This process was a child of a master process. The master process contains the good code and the child the bad. We were then able to keep track of the number of invocations of the child process and tear it down once it reached a certain number. We knew that we could get away with X invocations before the child process was corrupt.
Because of the nature of our problem, bringing up a fresh process enabled us to have another X invocations before repeating.
Any state was returned to the master process on a successful invocation. Any state gathered during an unsuccessful invocation was discarded and we started again.
Again, none of the above is "nice" but it worked for us.
For what it's worth, if I did this again, I'd use Akka and remote actors which would make all the sub-process, remoting etc far simpler.
That depends. Do you have the source code of this external application, i.e. can you recompile it? The easiest approach is obviously to fix the leak at its root. This might however be impractical. If the library, as you say, is implemented via native methods and some C code, I do not think that the problem has something to do with the Java garbage collector not properly working. Native methods and C code do not normally store their data on the JVM's heap and are therefore not garbage collected, i.e. it is the job of the library to clean up after itself.
If the leak is indeed in the bit of Java code that the library exposes, than there is a way. Memory leaks in Java occure by forgetting about references, e.g. consider the following example:
class Foo {
private ExpensiveObject eo;
Foo(ExpensiveObject eo) {
this.eo = eo;
}
}
The ExpensiveObject is alive (at least) as long as its referencing Foo instance. If you (or your library) do(es) not isolate instance life-cycles well enough, you get into trouble. If you do not have a chance to refactor, you can however use reflection to clean up the biggest mess from another place in your code:
void release(Foo foo) {
Field f = Foo.class.getDeclaredField("eo");
f.setAccessible(true);
f.set(foo, null);
}
This should however be considered a last-resort as it is quite a hack.
Alternatively, a better approach is normally to fork another instance of a JVM to do the dirty work. It seems like you are doing something similar already. By forking a JVM, you isolate the use of memory on a process level. Once the process dies, all memory is released by the OS. The problem with this approach is normally platform compatibility but as you already use a native library, this does not worsen your situation.
You say that you currently use files to communicate between these different processes. Why do you need to store data in a file? Rather consider using sockets or memory-mapped files (NIO), if performance is important for this matter.
I've got an Android project that heavily uses C++ JNI shared objects. In fact, I've got a Java object that manages resources allocated from JNI calls. On that particular Java object, I'm using a finalize() call to handle the freeing of those native resources when the object gets destroyed.
This all seems to work and I don't see any memory leaks, however, I've heard that you using Java finalizers is frowned upon (Effective java, 2nd edition page 27. Item 7: Avoid finalizers, etc.). Are there cases, such as the one I've described above, where using finalize() is appropriate? I'm not sure what else to do to ensure that those native resources get cleaned up.
I believe your case is one of the few where it's appropriate to use a finalizer.
To use exit(0) in C is not a good practice, if there are alternatives, since it does not free resources for example. But to use System.exit(0) in Java - how is it here? Could one trust the garbage collector in this context?
C language:
exit(0);
Java:
System.exit(0)
But to use System.exit(0) in java - how is it here? Could one trust the garbage-collector in this context?
When you call System.exit in Java, the garbage collector is not normally run1. However, in any JVM that I've ever heard of, there is something else that reclaims all of the objects that were allocated. (Typically it is handled at the operating system level.)
The fact that the GC doesn't run is only significant if you are relying on object finalizers to so something important before the JVM terminates.
Hypothetically, if your Java application used JNI (etc) to call native methods, then those methods could access system resources that might be problematic. However:
As a general rule the operating system does take care of such things. At least it does for modern versions of Linux and UNIX, AFAIK.
The garbage collector has no knowledge of those resources anyway. If the OS can't reclaim them, then the Java garbage collector won't help.
If you did need to clean up such resources acquired by a Java program (via native code) then the best approach would be to implement the cleanup in native code methods, and use a "shutdown hook" to run them. The shutdown hooks will be run if you call System.exit.
1 - A garbage collection will be performed on JVM exit if you have previously called runFinalizersOnExit(true). However, this is a deprecated method. The Oracle site explains it like this:
Q: Why is Runtime.runFinalizersOnExit deprecated?
A: Because it is inherently unsafe. It may result in finalizers being called on live objects while other threads are concurrently manipulating those objects, resulting in erratic behavior or deadlock. While this problem could be prevented if the class whose objects are being finalized were coded to "defend against" this call, most programmers do not defend against it. They assume that an object is dead at the time that its finalizer is called.
Further, the call is not "thread-safe" in the sense that it sets a VM-global flag. This forces every class with a finalizer to defend against the finalization of live objects!
In short, this is a dangerous approach, and it won't directly deal with the kind of resources that the OP is worried about.
Think of it like this. In C, you are building your source code into a binary file that will execute on it's own only conforming to the rules of logical programming and the rules set by your OS. The OS however does not manage your memory for you. It handles events and sends information to the hardware that tell it how to run, nothing more, nothing less. In java, all code is compiled into java's own bytecode. Upon execution it does not actually at any time communicate to the OS. The virtual machine designed to run that bytecode is what does the talking. When you call System.exit (0), you are telling the virtual machine that the app you are running is coming to a halt, from there the machine handles IT'S OWN MEMORY which just so happens to include anything you did not already remove via the garbage collector but only if the VM is exiting as well. Hope that helps
I'm making a fast-paced realtime Android game, and everything works great, but the first couple of seconds when the game starts are very laggy because the garbage collector is cleaning up after the loading thread. Sure, the player could wait a few seconds (like 10+ sec) because after its done it starts running perfectly smooth, but that looks really ugly and feels like the game is buggy.
Is there a way (or technique) to tell when its safe to start the game so the garbage collector won't start going crazy as soon as the real-time part begins? the big fat loading thread can't be reduced much without breaking things.
This seems like a case where System.gc() might help. It tells the system that this would be a good time to collect garbage. According to the documentation,
When control returns from the method call, the Java Virtual Machine has made a best effort to reclaim space from all discarded objects.
The docs also say, though, that the method "suggests" that objects be collected -- that is, there's no guarantee it'll help, particularly if you still have some references squirreled away. If it does work, it'll only collect objects that are not reachable at all from the running code, including the runtime. (That loader thread, for example, is not eligible for collection til it's finished running and your code has no more references to it.)
You can run System.gc() right before you start the game to manually force the garbage collector to run (and, according at least to the official JavaDoc here, finish before returning from this method call). However, the GC in general is nondeterministic and there is no guarantee that it will not be run again or, for that matter, that the call to System.gc() will do anything at all.
If you looked into this more deeply you will probably find that much (even most) of the "lagginess" is not the GC's fault. I suspect that it is mostly due to JIT compilation. Calling System.gc() could improve things, but I doubt that it will get rid of the lagginess entirely.