Relates :
|
|
Relates :
|
|
Relates :
|
|
Relates :
|
|
Relates :
|
|
Relates :
|
Name: tb29552 Date: 05/05/2003 FULL PRODUCT VERSION : java version "1.4.1_02" Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_02-b06) Java HotSpot(TM) Client VM (build 1.4.1_02-b06, mixed mode) FULL OS VERSION : Linux boulette 2.4.19-k7 #1 Tue Nov 19 03:01:13 EST 2002 i686 unknown unknown GNU/Linux A DESCRIPTION OF THE PROBLEM : When a method is to be called in the target JVM by the mean of the JDWP command "invokeMethod" (accessed for example with the "print" feature in jdb), the implementation of JDWP (on any platform) makes global references for every Object that is implied in the method invocation: Thread that executes the call, Class that contains the method to call (eventually Instance in which the method will be called) and method arguments which type is Object. This is done in fillInvokeRequest() in file j2se/src/share/back/invoker.c. When the method invocation terminates, global references are also created for the returned argument (if it is an Object) and for Exception that might have been thrown. These global refs are created to be sure that objects implied in the invocation will not be collected by the GC until the JDWP command is fully processed. When the result of the invocation is to be returned by JDWP, the global reference for the exception is deleted (at function invoker_completeInvokeRequest() in file j2se/src/share/back/invoker.c). A globalref retained for the execution thread is deleted too (at handleReportInvokeDoneCommand() in file j2se/src/share/back/eventHelper). At this time, the request is fully processed but globalreferences created for arguments are never deleted, which is an very annoying memory leak. A clean way to fix this memory leak is to modify function invoker_completeInvokeRequest() as followed: void invoker_completeInvokeRequest(jthread thread) { // the beginning of the function stays the same. // I only added code to its end. ... ... ... if (!detached) { outStream_initReply(&out, id); outStream_writeValue(env, &out, tag, returnValue); outStream_writeObjectTag(&out, exc); WRITE_GLOBAL_REF(env, &out, exc); outStream_sendReply(&out); } // here comes the change... /* * At this time, there's no need to retain global references on * arguments since the reply is processed. No one will deal with * this request ID anymore, so we must call deleteGlobalRef(). */ deleteGlobalRefs(env, request); if ((request->invokeType == INVOKE_CONSTRUCTOR) || (returnTypeTag(request->methodSignature) == JDWP_Tag_OBJECT)) { (*env)->DeleteGlobalRef(env, request->returnValue.l); } } STEPS TO FOLLOW TO REPRODUCE THE PROBLEM : When using jdb and that the debuggee is suspended in method foo(Object bar), just type "print bar.toString()" to trigger the JDWP command "invokeMethod". The problem can also be reproduced with jdk 1.4.2-beta EXPECTED VERSUS ACTUAL BEHAVIOR : EXPECTED - GlobalRefs created during the process of the command should all be deleted. This must be done here because they cannot be freed later by any other agent (such as a custom debugger or custom profiler) started in the target JVM. ACTUAL - GlobalRefs created for arguments of the method invocation are never deleted. This is responsible of an horrible memory leak ! My custom debugger/profiler uses JDWP to invoke a custom method in the target JVM that will request JVMPI heap dump to know every alive objects that are referencing a particular JVM Object. Because of this memory leak, my debugger always return wrong informations, i.e it reports GlobalRefs on Objects while actually no GlobalRef has been allocated by the debugged program itself :( ERROR MESSAGES/STACK TRACES THAT OCCUR : (no error displayed on screen) REPRODUCIBILITY : This bug can be reproduced always. ---------- BEGIN SOURCE ---------- public class incoming2 { public static void main(String[] args) { // break into main and do "print c1.toString()" in jdb Class c1=Object.class; System.out.println("1st: "+c1); } } ---------- END SOURCE ---------- CUSTOMER SUBMITTED WORKAROUND : This should really be fixed in JVM-side, since it's JDWP that is responsible of the allocation of the GlobalRefs. (Review ID: 185252) ======================================================================
|