Using the Raw Native Interface |
![]() Previous |
![]() Introduction |
![]() Next |
These sections describe the issues associated with garbage collection.
Probably the most important issue as far as native code and garbage collection is concerned is that while native code is executing no garbage collection can occur (other threads that try to do any garbage collection will block until the thread in native code returns to Java). The reason for this is so that the VM can avoid conservative scanning of native stacks which is often unreliable and can be a bottleneck to performance. A lot of native code simply does some quick calculation and returns so this isn't a problem but if the native code is going to perform some operation that could take some time we should explicitly enable and disable garbage collection around the slow code. Of course, enabling garbage collection means that any objects could move at any time invalidating any pointers we may have to those objects in native code. The simplest way to handle this is to inform the garbage collector of objects you're interested in before enabling GC using a GCFrame() with GCFramePush(). Object pointers kept in a GCFrame will be automatically updated if the object gets moved and when you're done you can tell the garbage collector of that fact using GCFramePop(). Here's a typical example:
void some_java_method(HObject *phobj1Unsafe, HObject *phobj2Unsafe) { // Keep a structure with all the objects we're interested in. struct { HObject *phobj1Safe; HObject *phobj2Safe; } gc; // Declare a GCFrame; GCFrame gcf; // Tell the garbage collector about our structure, it will initialize this // structure to null. GCFramePush(&gcf, &gc, sizeof(gc)); // Set the object ptr. gc.phobj1Safe = phobj1Unsafe; gc.phobj2Safe = phobj2Unsafe; // It's now safe to enable garbage collection. GCEnable(); // ...time passes...garbage collection occurs...objects move... // Disable gargbage collection so we can access objects safely. GCDisable(); // If GC moved our object then gc.hobjSafe will have been automatically // updated. gc.phobj1Safe->x = 42; gc.phobj2Safe->y = 33; // We're done. GCFramePop(&gcf); }
Note It's important to note that you must enable GC as many times as you disabled it and also call GCFramePop() before returning from native code back in to Java. Also, GCFrames are "strong" in the sense that having an object in GCFrame is considered to be equivalent to having a reference to that object so it won't get free'd by the garbage collector.
GCFrames are ideal for protecting objects on the stack but not in situations where you want to keep an object pointer longer than the lifetime of the function in global memory say. For situations like this you should use GCGetWeakPtr() and GCFreeWeakPtr() instead:
HObject **pphobjSafe = NULL; void some_java_methodA(HObject *phobjUnsafe) { // Allocate a weak ptr that we want to use later. pphobjSafe = GCGetWeakPtr(phobjUnsafe); } void some_java_methodB() { // Use the weak ptr we saved previously. *pphobjSafe->x = 42; GCFreeWeakPtr(pphobjSafe); }
As their names imply, these API's create "weak" pointers to objects such that they can be free'd by the garbage collector if no more references exist at which point the weak pointer becomes automatically invalid and you shouldn't call GCFreeWeakPtr() on it. If you know the object can't have been freed by the garbage collector then you should call GCFreeWeakPtr() when you no longer need to keep track of it.
If you call back in to Java from native code garbage collection may automatically be enabled by the VM if memory needs to be allocated. This means that any object pointers you need to use after the call must be protected either in a GCFrame or tracked via a weak pointer.