-
Bug
-
Resolution: Fixed
-
P3
-
5.0, 5.0u16
-
b03
-
x86
-
linux_redhat_3.0, windows_xp
Issue | Fix Version | Assignee | Priority | Status | Resolution | Resolved In Build |
---|---|---|---|---|---|---|
JDK-2174433 | 5.0u19 | Vaibhav Choudhary | P3 | Resolved | Fixed | b01 |
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.
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.
- backported by
-
JDK-2174433 Memory leak occurs in JVMTI(jdk5.0u16)
- Resolved
- duplicates
-
JDK-6469701 java.lang.Thread.getStackTrace() causes memory leaks in the VM
- Closed
-
JDK-2170883 java.lang.Thread.getStackTrace() causes memory leaks in the VM
- Closed
-
JDK-2170884 java.lang.Thread.getStackTrace() causes memory leaks in the VM
- Closed
- relates to
-
JDK-6751862 GrowableArray should be relased in jdk5.0u16
- Closed