JNI feature suggestion. A way to avoid the use of finalized objects.
0 posts in topic
Flat View  Flat View
TOPIC ACTIONS:
 

Posted By:   Jacob_Marner
Posted On:   Sunday, April 29, 2001 03:03 PM

Hi, I have summitted a feature request to the java.sun.com feature request forum and was asked to post it a forum get other people's opinion first. That is what I am doing now. Please comment on whether I have misunderstood something, missed something or whether I am right. ------------- Note: This text uses garbage collector terms from the book: Java platform performance, appendix A, which is available on-line from Sun. The main issue that I wish to address is the fact that is you access an object via a weak reference in native code (with JNI) then you have no way of telling whether t   More>>

Hi,

I have summitted a feature request to the java.sun.com feature

request forum and was asked to post it a forum get other people's

opinion first. That is what I am doing now.



Please comment on whether I have misunderstood something,

missed something or whether I am right.



-------------



Note: This text uses garbage collector terms from the book: Java platform

performance, appendix A, which is available on-line from Sun.



The main issue that I wish to address is the fact that is you access an

object via a weak reference in native code (with JNI) then you

have no way of telling whether the object has been finalized.



I suggest the JNI function NewLocalRef() and NewGlobalRef() is changed such that

using it on a weak reference obj it returns only non-null if the object

has not yet been collected.



I have not used the java.lang.ref.* objects but as far as I understand

from the documentation an object is no longer weakly reachable when

it has been collected. After this it might be finalized at any time. It

therefore makes sense to avoid the use of weak references that

points to objects not weakly referenced.



---------------



*** The problem this issue causes ***



Currently we have only one way to use an object referenced

with a weak reference in JNI:



jobject jobj = env->NewLocalRef(obj); // obj is a weak reference.

if (!env->IsSameObject(jobj,NULL))

... use jobj ...



We make a strong reference in the call to NewLocalRef() to make a strong

reference to avoid the case when the weakly referenced object is collected

after the call to IsSameObject() and its use.



In the above situation NewLocalRef() returns only NULL when the object

has been reclaimed by the system. This means that we might make a strong

reference to an object that has already been finalized or are queued for

finalization. In fact, it might be finalized at this instant if a VM that

runs finalizers in seperate threads are used.



In my case I have weak references to objects that has external resources

that must reclaimed upon finalization. The object has no external resources

after finalization and should therefore not be used. It is *not* enough

to set some variable in the finalize() method to say that the external

resources are released - because if the finalizer thread is interrupted

in its first line of finalize() this value is not set.



workaround : A temporary, not fully satisfactory, workaround is to delete

all weak references to an object from its finalizer. It may still go wrong

but chances are we will not use a that weak references to an object

that has been finalized.



---------------------



The full source of an example that shows how this goes wrong:

(Used Sun JDK 1.3.0_02 on Windows 98. Used Microsoft Visual C++

6.0 to compile the native part)



Bad.java:

============



class Bad

{

boolean legal = true;



protected void finalize()

{

legal = false;

// external clean-up goes here. The use of the

// object after this point is an error.

}



public static void main(String[] args)

{

System.loadLibrary("bug");



int count = 1;

while (true)

{

//System.gc(); // Uncomment this to keep garbage collector

// up to date. Avoids problem in most cases.

System.out.println(count);

generateReferences(count);

retrieveReferences(count);

count++;

}

}



public static void generateReferences(int count)

{

for (int i=0;i

{

Bad object = new Bad();

n_storeReference(object);

}

}

native static void n_storeReference(Bad object);



public static void retrieveReferences(int count)

{

for (int i=0;i

{

Bad object = n_retrieveReference();



if (object!=null && !object.legal)

{

System.out.println("Error! Object already finalized.");

System.exit(1);

}



// This is where we would use the object. If it is

// finalized then the external data is illegal.

}

}

native static Bad n_retrieveReference();

}





And the C++ files native.cpp that becomes bug.dll:

===================================



#include "Bad.h"



#include



std::list objectlist;



JNIEXPORT void JNICALL Java_Bad_n_1storeReference

(JNIEnv *env, jclass, jobject jobj)

{

jobject o = env->NewWeakGlobalRef(jobj);

objectlist.push_front(o);

}





JNIEXPORT jobject JNICALL Java_Bad_n_1retrieveReference

(JNIEnv *env, jclass)

{

if(!objectlist.empty())

{

jobject jobj = env->NewLocalRef(objectlist.back());

objectlist.pop_back();

if (!env->IsSameObject(jobj,NULL))

return jobj;

}

return NULL;

}



This program needs to be run for a while until the timing

of the use of the weak reference is right. On my computer it

happens after 120 iterations. If you turn on the call to

System.gc() it takes so long that I lost patience.



-----------

What do you think? Dou agree on this issue, or have I overlooked

something. Please comment.



B.Sc. Jacob Marner

   <<Less
About | Sitemap | Contact