United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-6751861 Memory leak occurs in JVMTI(jdk5.0u16)
JDK-6751861 : Memory leak occurs in JVMTI(jdk5.0u16)

Details
Type:
Bug
Submit Date:
2008-09-24
Status:
Resolved
Updated Date:
2011-02-16
Project Name:
JDK
Resolved Date:
2009-03-09
Component:
hotspot
OS:
linux_redhat_3.0,windows_xp
Sub-Component:
jvmti
CPU:
x86
Priority:
P3
Resolution:
Fixed
Affected Versions:
5.0,5.0u16
Fixed Versions:
5.0u18-rev (b03)

Related Reports
Backport:
Duplicate:
Duplicate:
Duplicate:
Relates:

Sub Tasks

Description
When a customer used JVMTI in jdk5, memory leaks. 
Specifically speaking, when a callback function is set for the event
of JVMTI_EVENT_THREAD_START, this leak occurs.

The following source code portions are based on jdk5.0u16.

When a call back function is set for the event of JVMTI_EVENT_THREAD_START,
every time Java application creates threads, JvmtiThreadState is created in JVM.
At the line# 49( constructor of JvmtiThreadState and GrowableArray),
the second argument is set to true.

----
  [hotspot/src/share/vm/prims/jvmtiThreadState.cpp]
   30 JvmtiThreadState::JvmtiThreadState(JavaThread* thread)
    ...
   47   // add all the JvmtiEnvThreadState to the new JvmtiThreadState
   48   int ec = JvmtiEnvBase::env_count();
   49   _env_thread_states    = new (ResourceObj::C_HEAP) GrowableArray<JvmtiEnvThreadState *>(ec+1,true);
    ...
   66 }
-----

When the second argument is true, the field "_data" in GrowableArray is allocated to c heap.
Because there is no destructor for GrowableArray, to call clear_and_deallocate() and
release _data are needed before the release of GrowableArray.

  [hotspot/src/share/vm/utilities/growableArray.cpp]
   31 GenericGrowableArray::GenericGrowableArray(int initial_size, int initial_len, GrET* filler, bool c_heap) {
   32   _len = initial_len;
   33   _max = initial_size;
   34   assert(_len >= 0 && _len <= _max, "initial_len too big");
   35   _arena = (c_heap ? (Arena*)1 : NULL);
   36   if (on_C_heap()) {
   37     _data = NEW_C_HEAP_ARRAY(GrET*, _max);
   38   } else {
   39     _data = NEW_RESOURCE_ARRAY(GrET*, _max);
   40   }
   41   for (int i = 0; i < _len; i++) _data[i] = filler;
   42 #ifdef ASSERT
   43   if (!on_C_heap()) {
   44     _nesting = Thread::current()->resource_area()->nesting();
   45   }
   46 #endif
   47 }
    ...
  222 void GenericGrowableArray::clear_and_deallocate() {
  223   assert(on_C_heap(),
  224          "clear_and_deallocate should only be called when on C heap");
  225   clear();
  226   if (_data != NULL) {
  227     FreeHeap(_data);
  228     _data = NULL;
  229   }
  230 }

However, there is no call for clear_and_deallocate() before _env_thread_states is discarded
in destructor, ~JvmtiThreadState().

  [hotspot/src/share/vm/prims/jvmtiThreadState.cpp]
   69 JvmtiThreadState::~JvmtiThreadState()   {
    ...
   79   int ec = env_count();
   80   assert(ec == JvmtiEnvBase::env_count(), "Should be one JvmtiEnvThreadState per environment");
   81   for (int i = 0; i < ec ; ++i) {
   82     JvmtiEnvThreadState *ets = _env_thread_states->at(i);
   83     _env_thread_states->at_put(i, NULL);
   84     delete ets;
   85   }
   86   FreeHeap(_env_thread_states);
   87   _env_thread_states = NULL;

So, every time JvmtiThreadState is created, which is, application creates threads, memory will leak.

                                    

Comments
EVALUATION

The bug description does not mention if the customer has tried jdk6 but the issue should already been fixed via the changes for the more general problem that was 6306746. Furthermore, this code was subsequently replaced in jdk6 but the changes for 6369191 and 6452240.
                                     
2008-09-24
SUGGESTED FIX

http://jpsesvr.sfbay.sun.com:8080/ctetools/CodeStore/2815/webrev/index.html
                                     
2009-01-21



Hardware and Software, Engineered to Work Together