-
Bug
-
Resolution: Fixed
-
P4
-
9
-
b81
Issue | Fix Version | Assignee | Priority | Status | Resolution | Resolved In Build |
---|---|---|---|---|---|---|
JDK-8141860 | emb-9 | David Lindholm | P4 | Resolved | Fixed | team |
JDK-8140845 | 8u91 | Mikael Gerdin | P4 | Resolved | Fixed | b01 |
JDK-8138640 | 8u72 | Mikael Gerdin | P4 | Closed | Fixed | b01 |
JDK-8147152 | emb-8u91 | Mikael Gerdin | P4 | Resolved | Fixed | b01 |
G1RootProcessor constructor allocate SubTasksDone object for _process_strong_tasks field(hotspot/src/share/vm/gc/g1/g1RootProcessor.cpp):
G1RootProcessor::G1RootProcessor(G1CollectedHeap* g1h, uint n_workers) :
_g1h(g1h),
_process_strong_tasks(new SubTasksDone(G1RP_PS_NumElements)),
_srs(n_workers),
_lock(Mutex::leaf, "G1 Root Scanning barrier lock", false, Monitor::_safepoint_check_never),
_n_workers_discovered_strong_classes(0) {}
SubTasksDone also allocate memory(hotspot/src/share/vm/gc/shared/workgroup.cpp):
SubTasksDone::SubTasksDone(uint n) :
_n_tasks(n), _tasks(NULL) {
_tasks = NEW_C_HEAP_ARRAY(uint, n, mtInternal);
guarantee(_tasks != NULL, "alloc failure");
clear();
}
But G1RootProcessor doesn't have destructor which will destroy SubTasksDone object when G1RootProcessor will go out from the scope. This leads to the memory leak in the following places:
hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp module:
void G1CollectedHeap::verify(bool silent, VerifyOption vo) {
...
{
G1RootProcessor root_processor(this, 1);
root_processor.process_all_roots(&rootsCl,
&cldCl,
&blobsCl);
}
...
void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info) {
...
{
G1RootProcessor root_processor(this, n_workers);
G1ParTask g1_par_task(this, _task_queues, &root_processor, n_workers);
// InitialMark needs claim bits to keep track of the marked-through CLDs.
if (collector_state()->during_initial_mark_pause()) {
ClassLoaderDataGraph::clear_claimed_marks();
}
// The individual threads will set their evac-failure closures.
if (PrintTerminationStats) {
G1ParScanThreadState::print_termination_stats_hdr();
}
workers()->run_task(&g1_par_task);
end_par_time_sec = os::elapsedTime();
// Closing the inner scope will execute the destructor
// for the G1RootProcessor object. We record the current
// elapsed time before closing the scope so that time
// taken for the destructor is NOT included in the
// reported parallel time.
}
...
hotspot/src/share/vm/gc/g1/g1MarkSweep.cpp module:
void G1MarkSweep::mark_sweep_phase1(bool& marked_for_unloading,
bool clear_all_softrefs) {
...
{
G1RootProcessor root_processor(g1h, 1);
root_processor.process_strong_roots(&GenMarkSweep::follow_root_closure,
&GenMarkSweep::follow_cld_closure,
&follow_code_closure);
}
...
void G1MarkSweep::mark_sweep_phase3() {
...
{
G1RootProcessor root_processor(g1h, 1);
root_processor.process_all_roots(&GenMarkSweep::adjust_pointer_closure,
&GenMarkSweep::adjust_cld_closure,
&adjust_code_closure);
}
...
G1RootProcessor::G1RootProcessor(G1CollectedHeap* g1h, uint n_workers) :
_g1h(g1h),
_process_strong_tasks(new SubTasksDone(G1RP_PS_NumElements)),
_srs(n_workers),
_lock(Mutex::leaf, "G1 Root Scanning barrier lock", false, Monitor::_safepoint_check_never),
_n_workers_discovered_strong_classes(0) {}
SubTasksDone also allocate memory(hotspot/src/share/vm/gc/shared/workgroup.cpp):
SubTasksDone::SubTasksDone(uint n) :
_n_tasks(n), _tasks(NULL) {
_tasks = NEW_C_HEAP_ARRAY(uint, n, mtInternal);
guarantee(_tasks != NULL, "alloc failure");
clear();
}
But G1RootProcessor doesn't have destructor which will destroy SubTasksDone object when G1RootProcessor will go out from the scope. This leads to the memory leak in the following places:
hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp module:
void G1CollectedHeap::verify(bool silent, VerifyOption vo) {
...
{
G1RootProcessor root_processor(this, 1);
root_processor.process_all_roots(&rootsCl,
&cldCl,
&blobsCl);
}
...
void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info) {
...
{
G1RootProcessor root_processor(this, n_workers);
G1ParTask g1_par_task(this, _task_queues, &root_processor, n_workers);
// InitialMark needs claim bits to keep track of the marked-through CLDs.
if (collector_state()->during_initial_mark_pause()) {
ClassLoaderDataGraph::clear_claimed_marks();
}
// The individual threads will set their evac-failure closures.
if (PrintTerminationStats) {
G1ParScanThreadState::print_termination_stats_hdr();
}
workers()->run_task(&g1_par_task);
end_par_time_sec = os::elapsedTime();
// Closing the inner scope will execute the destructor
// for the G1RootProcessor object. We record the current
// elapsed time before closing the scope so that time
// taken for the destructor is NOT included in the
// reported parallel time.
}
...
hotspot/src/share/vm/gc/g1/g1MarkSweep.cpp module:
void G1MarkSweep::mark_sweep_phase1(bool& marked_for_unloading,
bool clear_all_softrefs) {
...
{
G1RootProcessor root_processor(g1h, 1);
root_processor.process_strong_roots(&GenMarkSweep::follow_root_closure,
&GenMarkSweep::follow_cld_closure,
&follow_code_closure);
}
...
void G1MarkSweep::mark_sweep_phase3() {
...
{
G1RootProcessor root_processor(g1h, 1);
root_processor.process_all_roots(&GenMarkSweep::adjust_pointer_closure,
&GenMarkSweep::adjust_cld_closure,
&adjust_code_closure);
}
...
- backported by
-
JDK-8140845 Memory leak in G1 because G1RootProcessor doesn't have desctructor
-
- Resolved
-
-
JDK-8141860 Memory leak in G1 because G1RootProcessor doesn't have desctructor
-
- Resolved
-
-
JDK-8147152 Memory leak in G1 because G1RootProcessor doesn't have desctructor
-
- Resolved
-
-
JDK-8138640 Memory leak in G1 because G1RootProcessor doesn't have desctructor
-
- Closed
-
- relates to
-
JDK-8075210 Refactor strong root processing in order to allow G1 to evolve separately from GenCollectedHeap
-
- Resolved
-