JNA memory clean up - java

As per documentation of JNA for Memory class, finalize() method needs to be called when memory need to release which has no longer reference. But in JNA example, it is mentioned that Memory object is getting released when it is out of scope.
// note: like Memory, StringArray will free the contiguous block of memory it copied the Strings into when the instance goes out of scope
The questions are :
Does it mean, Memory class object is calling finalize() internally when it is out of scope and frees the underlying native memory?
The StringArray class and Memory class are same in behavior w.r.t. memory management? and how?

Update:
As of JNA 5.12.1, JNA's Memory class no longer uses finalize() to free memory. It registers a Cleaner (custom internal class based on JDK9+ Cleaner implementation) which releases the native memory using a separate thread.
Along with this change, Memory was made Closeable (JDK6) which extends AutoCloseable in JDK7+ implementations. You may release the native memory simply by calling close() or better, allocating the memory in a try-with-resources block:
try (Memory m = new Memory(123)) {
// use m
}
Original answer:
To elaborate on Matthias Bläsing's answer in light of the specific questions asked, I want to add a few points:
You generally don't directly call finalize(). It is called by the JVM as part of the garbage collection process.
In Memory the finalize() method simply calls the dispose() method. If you really want to get rid of memory immediately this would be the preferred method to call. But dispose() is protected so you'd need to extend Memory to take advantage of this method if you really felt the need to clean up native memory allocations.
One such subclass you might consider is one that extends Closeable, where the close() method implementation calls dispose() from the superclass. Then you could, for example, use a try with resources block and have the native memory (resource) cleaned up at the end of the block. You'd still have the Java Object hanging around until GC, of course.
Note that freeing native memory comes with a processing cost, however, and unless you're really short on memory it doesn't gain much as you still have the Java heap memory associated with the object until it is GC'd. If you're that short of memory and going to that level of detail to control the timing of the native allocation cleanup, you probably want to go directly to the malloc() and free() calls yourself and control it at a higher level, perhaps recycling/reusing it...
You also asked about StringArray, but the closer parallel to Memory is the NativeString objects which are members of the array. And in fact their internal implementation is a StringMemory object which extends Memory so it would behave identically; that is, free() the native memory via dispose() via finalize() at the point the NativeString is garbage collected by the JVM.

The Memory implementation of JNA relies on the java garbage collection (GC). Java has no functions to explicitly acquire memory of objects, the memory necessary to hold object data is managed by the VM, allocated when an object is instantiated.
The GC is the process, that frees all memory not referenced anymore. All classes in Java can declare a method finalize, which will be called by the GC when the objects of that class are about to be cleared and gives objects the option to do some final cleanup work. In case of JNA this cleanup is releasing the native memory, that is allocated outside the GC controlled area.
It should be noted, that using finalize is being deprecated and should not be done anymore, but switch to alternative methods also means introducing slightly different behavior, which is one of the reasons, that JNA still relies on GC for cleanup.

Related

Releasing a direct buffer in java and possible pitfalls

we have the following piece of code:
long buffer = ((DirectBuffer) ByteBuffer.allocateDirect(256)).address();
It seems that there is no reference to direct buffer (as an object) on the thread's stack. So, it means that that object is phantom-reachable.
DirectByteBuffer becomes phantom-reachable.
Garbage collection is performed (in separate thread), DirectByteBuffer Java object is collected and an entry is added to the
ReferenceQueue.
Cleaner thread reaches this entry and runs the registered clean-up action (in this case, it's java.nio.DirectByteBuffer.Deallocator
object), this action finally frees the native memory.
The citation comes from: Java - When does direct buffer released?
So, it is possible that allocated memory that can be freed. However, we have a pointer to that, buffer of type long. Therefore it is possible that we've got SIGSEGV or something like that.
My question is:
Does it mean that we can hurt ourself using DirectBuffer in that manner?
Your assumption of danger here is correct, with a caveat.
The backing buffer of the direct buffer can be freed at any point after the containing ByteBuffer object becomes eligible for garbage collection (the exact moment the native memory is freed is implementation dependent, but typically it happens approximately when finalizer for the ByteBuffer runs).
From standard Java, this "dangling pointer" doesn't pose a real problem since it just a long like another other and you can't use unsafely. Of course if you pass it to some native or Unsafe code and try to use it as a pointer things can blow up.
Strictly speaking, not in the exact manner as you described because you just store a long value into a long variable. With this value you can do nothing harmful in Java.
As soon as you pass this to some native (C/C++) code and start using this as the address to write stuff to you get get yourself into problems as the object's memory may already have been reclaimed by the garbage collector.
Therefore all this access should be done in the native code (JNI) where you can use the native API to tell the virtual machine that your native code holds a reference (or not anymore). You can than use the address() function in your native code to get the address and use it.

Monitor Java objects allocation/deallocation in a specific method

I am wondering if there is any lightweight approach to (roughly) measure how much memory a given Java class is using. Let's consider the following interface:
interface MyAction <T, R> {
R execute(T item);
}
I would like to know how much memory all the objects instantiated as fields or as variables in the overrided execute method are using. Of course, it should also take into account every object created when invoking other methods.
As far as I could understand (reading this reply) the best option would be to:
Patch JVM bytecode through ASM framework and place hooks before any of the following instructions: new, newarray, anewarray, multianewarray.
Intercept all JNI calls (if any) by altering JNI function table.
Intercept all VMObjectAlloc events.
Those 3 steps would cover every possible allocation, however I could not figure out if there is any good method for tracking objects deallocation.
I would patch the finalize method bytecode in order to get notified about object gc deallocation and intercept all ObjectFree events (only for tagged objects). I am quite sure that this will not cover all the deallocation event, thus I wonder if there is some known technique (which I could not find out) that may help me in solving this problem.
Thank you in advance.
Since you are interested in the amount of allocated memory, not the every single allocated object, you may use a simpler approach.
There is a method ThreadMXBean.getThreadAllocatedBytes that returns the cumulative amount of memory allocated by the given thread. You just need to record the counter before calling execute and after. The difference will be the estimated total memory allocated by the method (considering that it does not span several threads).
Here is how to get the instance of com.sun.management.ThreadMXBean:
com.sun.management.ThreadMXBean mxBean =
(com.sun.management.ThreadMXBean) ManagementFactory.getThreadMXBean();
There is no such event as object deallocation in Java. You cannot find whether an object is reachable or not until full GC. Even GC does not "deallocate" objects - it usually just walks through live objects, and treats everything else as free space.
If you need to find how Java heap changes after calling a method, you may create a heap snapshot before and after the call.

Is there any way that I can free up memory in the java code that is generated to bind C code via JNI/JNA?

I am using a java library that use JNA to bind to the original C library (That library is called Leptonica). I encountered a situation where free(data) has to be called in the C code to free up the memory. But, is there any function in java that I can free up the memory?
In the C code
void ImageData::SetPixInternal(Pix* pix, GenericVector<char>* image_data) {
l_uint8* data;
size_t size;
pixWriteMem(&data, &size, pix, IFF_PNG);
pixDestroy(&pix);
image_data->init_to_size(size, 0);
memcpy(&(*image_data)[0], data, size);
free(data);
}
The function pixWriteMem() will create and allocate memory to the "data", which you need to do free(data) to free up the memory later.
In Java code, I can only access pixWriteMem(), not the SetPixInternal(), so I have no way to free up the "data", which create a memory leak.
The other comments and answers here all seem to be suggesting that you just rely on the garbage collector or tell the garbage collector to run. That is not the correct answer for memory allocated in C and being used in Java via JNI.
It looks like that execution() does free the memory. The last line you show us is free(data). Still, to answer your the question as you asked it, the answer is "not directly." If you have the ability to add to the C code, you could create another C function which frees the data and then call that using JNI. Perhaps there is more that we are not seeing which relates better to your concern about the memory leak?
Also, be careful about freeing memory allocated by a library you are using. You should make sure that the library doesn't still need it and is leaking it before you go trying to free it.
And now back to memory management in general...
Java is indeed a garbage-collected language. This means that you do not specifically delete objects. Instead, you make sure there are no references to it, then the garbage collector takes care of the memory management. This does not mean that Java is free from memory leaks, as there are ways to accidentally keep a reference hanging around such that the object never gets garbage collected. If you have a situation like this, you might want to read up on the different kinds of references in Java (strong/weak/etc.).
Again, this is not the problem here. This is a C/Java hybrid, and the code in question is in C being called by Java. In C, you allocate the memory you want to use and then you need to free the memory yourself when you are done with it. Even if the C code is being run by Java via the JNI, you are still responsible for your own memory. You cannot just malloc() a bunch of memory and expect the Java garbage collector to know when to clean it up. Hence the OP's question.
If you need to add the functionality yourself to do a free, even without the source code for the C part, you might still be able to write your own C interface for freeing the memory if you have access to the pointer to the memory in question. You could write basically a tiny library that just frees the memory for you, make the JNI interface for it, and pass the pointer to that. If you go this route then, depending on your OS, you might need to guarantee that your tiny free library's native code is running in the same process as the rest of the native code, or if not the same process then at least that the process you run it from has write access to the memory owned by the other code's process; this memory/process issue is probably not an issue in your case, but I'm throwing it out there for completeness.
In Java code, I can only access createData(), not the excution(), so I have no way to free up the "data", which create a memory leak.
Then it sucks to be you.
Seriously, if you want to free memory allocated by a native method and not freed before that method returns, then you need to maintain a handle of some kind on that memory and later pass it to another native method that will free the memory. If you do not presently have such a native method available, then you'll need to create one.
The other question is how to ensure that the needed native method is invoked. Relying on users to invoke it, directly or indirectly, leaves you open to memory leaks should users fail to do so. There are two main ways to solve that problem:
Give your class a finalizer that ensures the memory is freed. This is the core use case for finalizers, but even so, there are good reasons to prefer to avoid writing them. The other alternative is to
Create a reference object (SoftReference, WeakReference, or PhantomReference), associate the reference with a mechanism for freeing the native-allocated memory belonging to the referenced Java object (but not via that object), and register that object with a reference queue. The reference will be enqueued when the object is GC'd, at which point you know to free the native-allocated memory.
That does not necessarily mean that you should prevent users from explicitly freeing the memory, for with enough bookkeeping you can track whether anything still needs to be freed at any given time. Allowing users to release resources explicitly may help keep your overall resource usage lower. But if you want to avoid memory leaks then you need to have a fallback.
No there is no function like C's free() in Java. But you can suggest garbage collector to run by calling System.gc()

Preventing native memory leak by customizing garbage collector?

Let's say I'm writing an API in java that refers to some native C libraries, that requires destructors to be called explicitly. If the destructors are not called, I run out of native memory.
Is there a way to protect users of my API from calling the destructors explicitly, by having the garbage collector call the destructors somehow? (perhaps based on some estimate I make of the size of the used native memory?)
I know Java doesn't have its garbage collector as part of the Java API, but perhaps there is some way to get this implemented?
One alternative if you have control over creation of your objects is to reference them with a WeakReference using the constructor that takes a ReferenceQueue. When they get out of scope, the Reference will be queued and you can have your own thread polling the queue and call some clean up function.
Why?
Well, it is slightly more efficient than adding finalizers to your classes (because it forces the gc to do some special handling of them).
Edit: The following two (variations of the same article) describes it:
http://java.sun.com/developer/technicalArticles/javase/finalization/
http://www.devx.com/Java/Article/30192
Peter Lawrey has a very good point when he says:
Even so, waiting for the GC to cleanup can be inefficient and you may want to expose a means of explicitly cleaning up the resource if its required.
Whenever you can assume your users to be on Java7, take a look at java.lang.AutoCloseable as it will help them do that automatically when using the new try-with-resources.
In addition to use finalize(), you may need to trigger a GC if you run out of resources to make the call, however a GC hasn't been run.
The ByteBuffer.allocateDirect() has this issue. It need the GC to clean up its ByteBuffers, However, you can reach your maximum direct memory before a GC is triggered, so the code has to detect this and triggers a System.gc() explicitly.
Even so, waiting for the GC to cleanup can be inefficient and you may want to expose a means of explicitly cleaning up the resource if its required.
Garbage collector will call finalize() of Java objects when the Java object is about to be GCd, and inside the finalize, you could call the destructor. Just make a new Java object for every destructor that needs to be called, and keep reference to that Java object until when you want to call the destructor.
In practice, finalize() will be called sooner or later (even though technically Java makes no guarantee that any particular object will ever be GCd). The only exception is if the object is still around when the process is shutting down: then it may indeed never get GCd.

GC.AddMemoryPressure equivalent in Java

Project: Java, JNI (C++), Android.
I'm going to manage native C++ object's lifetime by creating a managed wrapper class, which will hold a pointer to the native object (as a long member) and will delete the native object in it's overridden finalize() method. See this question for details.
The C++ object does not consume other types of resources, only memory. The memory footprint of the object is not extremely high, but it is essentially higher than 64 bit of a long in Java. Is there any way to tell Java's GC, that my wrapper is responsible for more than just a long value, and it's not a good idea to create millions of such objects before running garbage collection? In .NET there is a GC's AddMemoryPressure() method, which is there for exactly this purpose. Is there an equivalent in Java?
After some more googling, I've found a good article from IBM Research Center.
Briefly, they recommend using Java heap instead of native heap for native objects. This way memory pressure on JVM garbage collector is more realistic for the native objects, referenced from Java code through handles.
To achieve this, one needs to override the default C++ heap allocation and deallocation functions: operator new and operator delete. In the operator new, if JVM is available (JNI_OnLoad has been already called), then the one calls NewByteArray and GetByteArrayElements, which returns the allocated memory needed. To protect the created ByteArray from being garbage collected, the one also need to create a NewGlobalRef to it, and store it e.g. in the same allocated memory block. In this case, we need to allocate as much memory as requested, plus the memory for the references. In the operator delete, the one needs to DeleteGlobalRef and ReleaseByteArrayElements. In case JVM is not available, the one uses native malloc and free functions instead.
I believe that native memory is allocated outside the scope of Java's heap size. Meaning, you don't have to worry about your allocation taking memory away from the value you reserved using -Xmx<size>.
That being said, you could use ByteBuffer.allocateDirect() to allocate a buffer and GetDirectBufferAddress to access it from your native code. You can control the size of the direct memory heap using -XX:MaxDirectMemorySize=<size>

Categories