Using the Raw Native Interface |
![]() Previous |
![]() Introduction |
![]() Index |
![]() Next |
These sections describe the issues associated with garbage collection.
No garbage collection can occur while native code is executing (other threads that try to do any garbage collection will block until the thread in native code returns to Java). This is probably the most important issue as far as native code and garbage collection are concerned. The reason for this is so 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 does some quick calculation and returns, so this isn't a problem. However, if the native code is going to perform some operation that could take some time, 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. When you're done, you can inform the garbage collector using GCFramePop(). The following is 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. For situations like this, 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 APIs create "weak" pointers to objects such that they can be freed by the garbage collector if no more references exist. At this point, the weak pointer becomes invalid automatically: Do not call GCFreeWeakPtr() on it. If you know the object can't have been freed by the garbage collector, then 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 by a weak pointer.
© 1997 Microsoft Corporation. All rights reserved. Legal Notices.