JDK-7122253 : Instrumentation.retransformClasses() leaks class bytes
  • Type: Bug
  • Component: hotspot
  • Sub-Component: jvmti
  • Affected Version: hs20
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2011-12-16
  • Updated: 2013-09-12
  • Resolved: 2012-03-29
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 6 JDK 7 JDK 8 Other
6u60Fixed 7-poolResolved 8Fixed hs23Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
java.lang.instrument.Instrumentation.retransoformClasses() leaks
memory for the retransformed class or classes.

As part of the work on this bug, the following SDK/JDK test
will be added:

    java/lang/instrument/RetransformBigClass.sh
The attached output.6u29_server_base.with_transformer.log tells
the tale for the Server VM on Solaris X86. Version info is:

java version "1.6.0-201112142258.dcubed.exp_bofa_leak"
Java(TM) SE Runtime Environment (build 1.6.0-201112142258.dcubed.exp_bofa_leak-jprtadm_14_Dec_2011_15_17-b00)
Java HotSpot(TM) Server VM (build 20.4-b02, mixed mode)

The above bits are with the fix for 7121600 in place.


Here is trace info for the first RedefineClasses() call:

RedefineClasses-0x1: loading name=BigClass (avail_mem=1183084K)
RedefineClasses-0x1: loaded name=BigClass (avail_mem=1178924K)
RedefineClasses-0x1: redefined name=BigClass, count=1 (avail_mem=1178884K)


Here is trace info for the last RedefineClasses() call:

RedefineClasses-0x1: loading name=BigClass (avail_mem=134072K)
RedefineClasses-0x1: loaded name=BigClass (avail_mem=133040K)
RedefineClasses-0x1: redefined name=BigClass, count=1000 (avail_mem=133040K)


Here's the math for leak:

1178884 - 133040
1045844
. / 1024
1021.3320

So we leaked just over 1GB in 1000 RedefineRetransform() calls.
The attached output.6u29_client_base.with_transformer.log tells
the tale for the Client VM on Solaris X86. Version info is:

java version "1.6.0-201112142258.dcubed.exp_bofa_leak"
Java(TM) SE Runtime Environment (build 1.6.0-201112142258.dcubed.exp_bofa_leak-jprtadm_14_Dec_2011_15_17-b00)
Java HotSpot(TM) Client VM (build 20.4-b02, mixed mode)

The above bits are with the fix for 7121600 in place.


Here is trace info for the first RedefineClasses() call:

RedefineClasses-0x1: loading name=BigClass (avail_mem=1112544K)
RedefineClasses-0x1: loaded name=BigClass (avail_mem=1108400K)
RedefineClasses-0x1: redefined name=BigClass, count=1 (avail_mem=1108352K)


Here is trace info for the last RedefineClasses() call:

RedefineClasses-0x1: loading name=BigClass (avail_mem=151196K)
RedefineClasses-0x1: loaded name=BigClass (avail_mem=150160K)
RedefineClasses-0x1: redefined name=BigClass, count=1000 (avail_mem=150160K)


Here's the math for leak:

1108352 - 150160
958192
. / 1024
935.7343

So we leaked almost 1GB in 1000 RedefineRetransform() calls.

Comments
EVALUATION http://hg.openjdk.java.net/lambda/lambda/hotspot/rev/4ceaf61479fc
22-03-2012

EVALUATION http://hg.openjdk.java.net/hsx/hotspot-main/hotspot/rev/4ceaf61479fc
30-12-2011

EVALUATION http://hg.openjdk.java.net/hsx/hotspot-rt/hotspot/rev/4ceaf61479fc
22-12-2011

SUGGESTED FIX The proposed fix for code review round 0 is attached as 7122253-webrev-cr0.tgz. This archive contains webrevs for JDK6u29/HSX-20, JDK7u4/HSX-23-B06 and JDK8/HSX-23-B08.
22-12-2011

PUBLIC COMMENTS JVM/TI RetransformClasses() class file byte caching was introduced in JDK6-B40. Here are the relevant code snippets: src/share/vm/prims/jvmtiRedefineClasses.cpp: 1.17 transfer_old_native_function_registrations(); 1.1 1.37 // The class file bytes from before any retransformable agents mucked 1.37 // with them was cached on the scratch class, move to the_class. 1.37 // Note: we still want to do this if nothing needed caching since it 1.37 // should get cleared in the_class too. 1.37 the_class->set_cached_class_file(scratch_class->get_cached_class_file_bytes(), 1.37 scratch_class->get_cached_class_file_len()); 1.37 The above set_cached_class_file() call is where the previous cached value (if any) gets lost. Here is the delta that made the above changes: D 1.37 05/05/20 22:56:19 rfield 83 82 00013/00004/01858 MRs: COMMENTS: 4772582: JVM TI - multiple independent simultaneous instrumenting agents - RetransformClasses Add class file caching; Load kind src/share/vm/runtime/classFileParser.cpp: 1.248.1.2 // So that JVMTI can cache class file in the state before retransformable agents 1.248.1.2 // have modified it 1.248.1.1 unsigned char *cached_class_file_bytes = NULL; 1.248.1.1 jint cached_class_file_length; 1.248.1.1 1.242 ClassFileStream* cfs = stream(); <snip> 1.190 if (JvmtiExport::should_post_class_file_load_hook()) { 1.187.1.1 unsigned char* ptr = cfs->buffer(); 1.192 unsigned char* end_ptr = cfs->buffer() + cfs->length(); 1.138.3.1 1.248.1.1 JvmtiExport::post_class_file_load_hook(name, class_loader, protection_domain, 1.248.1.1 &ptr, &end_ptr, 1.248.1.1 &cached_class_file_bytes, 1.248.1.1 &cached_class_file_length); The above snippets of code are where the cached class file bytes are anchored in order to get filled in by the ClassFileLoadHook event handler. cached_class_file_bytes is initialized to zero here instead of being looked up on 'the_class'. Here's the delta that made the above changes: D 1.248.1.1 05/05/20 22:59:45 rfield 450 449 00014/00001/03713 MRs: COMMENTS: 4772582: JVM TI - multiple independent simultaneous instrumenting agents - RetransformClasses Add class file caching src/share/vm/prims/jvmtiExport.cpp 1.102 _cached_data_ptr = cached_data_ptr; 1.102 *_cached_length_ptr = 0; 1.102 *_cached_data_ptr = NULL; The above snippet of code is where the cache class file bytes would get lost even if we had copied the pointer from 'the_class'. Here is the delta that made the above changes: D 1.102 05/05/20 22:52:44 rfield 181 180 00159/00069/02319 MRs: COMMENTS: 4772582: JVM TI - multiple independent simultaneous instrumenting agents - RetransformClasses Create CFLH poster class to: add class file caching, and use new CFLH order So this memory leak has been around since JDK6-B40.
20-12-2011

EVALUATION ClassFileParser::parseClassFile() is the anchor point for the caches during class file parsing. It should use the "class_being_redefined" cache on the JvmtiThreadState to find the cache values for "the_class" so they can be used during the parsing of "scratch_class".
17-12-2011

EVALUATION The instanceKlass:_cached_class_file_bytes field is getting over written so we're leaking a malloc()'ed array the size of the class bytes. This leak happens on the second and subsequent calls to JVM/TI RetransformClasses().
17-12-2011