jdk

Форк
0
/
memoryManager.cpp 
327 строк · 11.6 Кб
1
/*
2
 * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
 *
5
 * This code is free software; you can redistribute it and/or modify it
6
 * under the terms of the GNU General Public License version 2 only, as
7
 * published by the Free Software Foundation.
8
 *
9
 * This code is distributed in the hope that it will be useful, but WITHOUT
10
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12
 * version 2 for more details (a copy is included in the LICENSE file that
13
 * accompanied this code).
14
 *
15
 * You should have received a copy of the GNU General Public License version
16
 * 2 along with this work; if not, write to the Free Software Foundation,
17
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
 *
19
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
 * or visit www.oracle.com if you need additional information or have any
21
 * questions.
22
 *
23
 */
24

25
#include "precompiled.hpp"
26
#include "classfile/javaClasses.hpp"
27
#include "classfile/vmSymbols.hpp"
28
#include "memory/allocation.inline.hpp"
29
#include "memory/universe.hpp"
30
#include "oops/oop.inline.hpp"
31
#include "oops/oopHandle.inline.hpp"
32
#include "runtime/atomic.hpp"
33
#include "runtime/handles.inline.hpp"
34
#include "runtime/javaCalls.hpp"
35
#include "runtime/mutexLocker.hpp"
36
#include "services/lowMemoryDetector.hpp"
37
#include "services/management.hpp"
38
#include "services/memoryManager.hpp"
39
#include "services/memoryPool.hpp"
40
#include "services/memoryService.hpp"
41
#include "services/gcNotifier.hpp"
42
#include "utilities/dtrace.hpp"
43

44
MemoryManager::MemoryManager(const char* name)
45
  : _pools(),
46
    _num_pools(0),
47
    _name(name),
48
    _memory_mgr_obj(),
49
    _memory_mgr_obj_initialized(false)
50
{}
51

52
int MemoryManager::add_pool(MemoryPool* pool) {
53
  int index = _num_pools;
54
  assert(index < MemoryManager::max_num_pools, "_num_pools exceeds the max");
55
  if (index < MemoryManager::max_num_pools) {
56
    _pools[index] = pool;
57
    _num_pools++;
58
  }
59
  pool->add_manager(this);
60
  return index;
61
}
62

63
bool MemoryManager::is_manager(instanceHandle mh) const {
64
  if (Atomic::load_acquire(&_memory_mgr_obj_initialized)) {
65
    return mh() == _memory_mgr_obj.resolve();
66
  } else {
67
    return false;
68
  }
69
}
70

71
MemoryManager* MemoryManager::get_code_cache_memory_manager() {
72
  return new MemoryManager("CodeCacheManager");
73
}
74

75
MemoryManager* MemoryManager::get_metaspace_memory_manager() {
76
  return new MemoryManager("Metaspace Manager");
77
}
78

79
instanceOop MemoryManager::get_memory_manager_instance(TRAPS) {
80
  // Lazily create the manager object.
81
  // Must do an acquire so as to force ordering of subsequent
82
  // loads from anything _memory_mgr_obj points to or implies.
83
  if (!Atomic::load_acquire(&_memory_mgr_obj_initialized)) {
84
    // It's ok for more than one thread to execute the code up to the locked region.
85
    // Extra manager instances will just be gc'ed.
86
    Klass* k = Management::sun_management_ManagementFactoryHelper_klass(CHECK_NULL);
87

88
    Handle mgr_name = java_lang_String::create_from_str(name(), CHECK_NULL);
89

90
    JavaValue result(T_OBJECT);
91
    JavaCallArguments args;
92
    args.push_oop(mgr_name);    // Argument 1
93

94
    Symbol* method_name = nullptr;
95
    Symbol* signature = nullptr;
96
    if (is_gc_memory_manager()) {
97
      Klass* extKlass = Management::com_sun_management_internal_GarbageCollectorExtImpl_klass(CHECK_NULL);
98
      // com.sun.management.GarbageCollectorMXBean is in jdk.management module which may not be present.
99
      if (extKlass != nullptr) {
100
        k = extKlass;
101
      }
102

103
      method_name = vmSymbols::createGarbageCollector_name();
104

105
      signature = vmSymbols::createGarbageCollector_signature();
106
      args.push_oop(Handle());      // Argument 2 (for future extension)
107
    } else {
108
      method_name = vmSymbols::createMemoryManager_name();
109
      signature = vmSymbols::createMemoryManager_signature();
110
    }
111

112
    if (k == nullptr) {
113
      fatal("Should have the ManagementFactoryHelper or GarbageCollectorExtImpl class");
114
      return nullptr; // silence the compiler
115
    }
116

117
    InstanceKlass* ik = InstanceKlass::cast(k);
118

119
    JavaCalls::call_static(&result,
120
                           ik,
121
                           method_name,
122
                           signature,
123
                           &args,
124
                           CHECK_NULL);
125

126
    // Verify we didn't get a null manager.  If that could happen then we'd
127
    // need to return immediately rather than continuing on and recording the
128
    // manager has been created.
129
    oop m = result.get_oop();
130
    guarantee(m != nullptr, "Manager creation returned null");
131
    instanceHandle mgr(THREAD, (instanceOop)m);
132

133
    // Allocate global handle outside lock, to avoid any lock nesting issues
134
    // with the Management_lock.
135
    OopHandle mgr_handle(Universe::vm_global(), mgr());
136

137
    // Get lock since another thread may have created and installed the instance.
138
    MutexLocker ml(THREAD, Management_lock);
139

140
    if (Atomic::load(&_memory_mgr_obj_initialized)) {
141
      // Some other thread won the race.  Release the handle we allocated and
142
      // use the other one.  Relaxed load is sufficient because flag update is
143
      // under the lock.
144
      mgr_handle.release(Universe::vm_global());
145
    } else {
146
      // Record the object we created via call_special.
147
      assert(_memory_mgr_obj.is_empty(), "already set manager obj");
148
      _memory_mgr_obj = mgr_handle;
149
      // Record manager has been created.  Release matching unlocked acquire,
150
      // to safely publish the manager object.
151
      Atomic::release_store(&_memory_mgr_obj_initialized, true);
152
    }
153
  }
154

155
  return (instanceOop)_memory_mgr_obj.resolve();
156
}
157

158
GCStatInfo::GCStatInfo(int num_pools) {
159
  // initialize the arrays for memory usage
160
  _before_gc_usage_array = NEW_C_HEAP_ARRAY(MemoryUsage, num_pools, mtInternal);
161
  _after_gc_usage_array  = NEW_C_HEAP_ARRAY(MemoryUsage, num_pools, mtInternal);
162
  _usage_array_size = num_pools;
163
  clear();
164
}
165

166
GCStatInfo::~GCStatInfo() {
167
  FREE_C_HEAP_ARRAY(MemoryUsage*, _before_gc_usage_array);
168
  FREE_C_HEAP_ARRAY(MemoryUsage*, _after_gc_usage_array);
169
}
170

171
void GCStatInfo::set_gc_usage(int pool_index, MemoryUsage usage, bool before_gc) {
172
  MemoryUsage* gc_usage_array;
173
  if (before_gc) {
174
    gc_usage_array = _before_gc_usage_array;
175
  } else {
176
    gc_usage_array = _after_gc_usage_array;
177
  }
178
  gc_usage_array[pool_index] = usage;
179
}
180

181
void GCStatInfo::clear() {
182
  _index = 0;
183
  _start_time = 0L;
184
  _end_time = 0L;
185
  for (int i = 0; i < _usage_array_size; i++) ::new (&_before_gc_usage_array[i]) MemoryUsage();
186
  for (int i = 0; i < _usage_array_size; i++) ::new (&_after_gc_usage_array[i]) MemoryUsage();
187
}
188

189

190
GCMemoryManager::GCMemoryManager(const char* name) :
191
  MemoryManager(name) {
192
  _num_collections = 0;
193
  _last_gc_stat = nullptr;
194
  _last_gc_lock = new Mutex(Mutex::nosafepoint, "GCMemoryManager_lock");
195
  _current_gc_stat = nullptr;
196
  _num_gc_threads = 1;
197
  _notification_enabled = false;
198
}
199

200
GCMemoryManager::~GCMemoryManager() {
201
  delete _last_gc_stat;
202
  delete _last_gc_lock;
203
  delete _current_gc_stat;
204
}
205

206
void GCMemoryManager::add_pool(MemoryPool* pool) {
207
  add_pool(pool, true);
208
}
209

210
void GCMemoryManager::add_pool(MemoryPool* pool, bool always_affected_by_gc) {
211
  int index = MemoryManager::add_pool(pool);
212
  _pool_always_affected_by_gc[index] = always_affected_by_gc;
213
}
214

215
void GCMemoryManager::initialize_gc_stat_info() {
216
  assert(MemoryService::num_memory_pools() > 0, "should have one or more memory pools");
217
  _last_gc_stat = new GCStatInfo(MemoryService::num_memory_pools());
218
  _current_gc_stat = new GCStatInfo(MemoryService::num_memory_pools());
219
  // tracking concurrent collections we need two objects: one to update, and one to
220
  // hold the publicly available "last (completed) gc" information.
221
}
222

223
void GCMemoryManager::gc_begin(bool recordGCBeginTime, bool recordPreGCUsage,
224
                               bool recordAccumulatedGCTime) {
225
  assert(_last_gc_stat != nullptr && _current_gc_stat != nullptr, "Just checking");
226
  if (recordAccumulatedGCTime) {
227
    _accumulated_timer.start();
228
  }
229
  // _num_collections now increases in gc_end, to count completed collections
230
  if (recordGCBeginTime) {
231
    _current_gc_stat->set_index(_num_collections+1);
232
    _current_gc_stat->set_start_time(Management::timestamp());
233
  }
234

235
  if (recordPreGCUsage) {
236
    // Keep memory usage of all memory pools
237
    for (int i = 0; i < MemoryService::num_memory_pools(); i++) {
238
      MemoryPool* pool = MemoryService::get_memory_pool(i);
239
      MemoryUsage usage = pool->get_memory_usage();
240
      _current_gc_stat->set_before_gc_usage(i, usage);
241
      HOTSPOT_MEM_POOL_GC_BEGIN(
242
        (char *) name(), strlen(name()),
243
        (char *) pool->name(), strlen(pool->name()),
244
        usage.init_size(), usage.used(),
245
        usage.committed(), usage.max_size());
246
    }
247
  }
248
}
249

250
// A collector MUST, even if it does not complete for some reason,
251
// make a TraceMemoryManagerStats object where countCollection is true,
252
// to ensure the current gc stat is placed in _last_gc_stat.
253
void GCMemoryManager::gc_end(bool recordPostGCUsage,
254
                             bool recordAccumulatedGCTime,
255
                             bool recordGCEndTime,
256
                             bool countCollection,
257
                             GCCause::Cause cause,
258
                             bool allMemoryPoolsAffected,
259
                             const char* message) {
260
  if (recordAccumulatedGCTime) {
261
    _accumulated_timer.stop();
262
  }
263
  if (recordGCEndTime) {
264
    _current_gc_stat->set_end_time(Management::timestamp());
265
  }
266

267
  if (recordPostGCUsage) {
268
    int i;
269
    // keep the last gc statistics for all memory pools
270
    for (i = 0; i < MemoryService::num_memory_pools(); i++) {
271
      MemoryPool* pool = MemoryService::get_memory_pool(i);
272
      MemoryUsage usage = pool->get_memory_usage();
273

274
      HOTSPOT_MEM_POOL_GC_END(
275
        (char *) name(), strlen(name()),
276
        (char *) pool->name(), strlen(pool->name()),
277
        usage.init_size(), usage.used(),
278
        usage.committed(), usage.max_size());
279

280
      _current_gc_stat->set_after_gc_usage(i, usage);
281
    }
282

283
    // Set last collection usage of the memory pools managed by this collector
284
    for (i = 0; i < num_memory_pools(); i++) {
285
      MemoryPool* pool = get_memory_pool(i);
286
      MemoryUsage usage = pool->get_memory_usage();
287

288
      if (allMemoryPoolsAffected || pool_always_affected_by_gc(i)) {
289
        // Compare with GC usage threshold
290
        pool->set_last_collection_usage(usage);
291
        LowMemoryDetector::detect_after_gc_memory(pool);
292
      }
293
    }
294
  }
295

296
  if (countCollection) {
297
    _num_collections++;
298
    // alternately update two objects making one public when complete
299
    {
300
      MutexLocker ml(_last_gc_lock, Mutex::_no_safepoint_check_flag);
301
      GCStatInfo *tmp = _last_gc_stat;
302
      _last_gc_stat = _current_gc_stat;
303
      _current_gc_stat = tmp;
304
      // reset the current stat for diagnosability purposes
305
      _current_gc_stat->clear();
306
    }
307

308
    if (is_notification_enabled()) {
309
      GCNotifier::pushNotification(this, message, GCCause::to_string(cause));
310
    }
311
  }
312
}
313

314
size_t GCMemoryManager::get_last_gc_stat(GCStatInfo* dest) {
315
  MutexLocker ml(_last_gc_lock, Mutex::_no_safepoint_check_flag);
316
  if (_last_gc_stat->gc_index() != 0) {
317
    dest->set_index(_last_gc_stat->gc_index());
318
    dest->set_start_time(_last_gc_stat->start_time());
319
    dest->set_end_time(_last_gc_stat->end_time());
320
    assert(dest->usage_array_size() == _last_gc_stat->usage_array_size(),
321
           "Must have same array size");
322
    size_t len = dest->usage_array_size() * sizeof(MemoryUsage);
323
    memcpy(dest->before_gc_usage_array(), _last_gc_stat->before_gc_usage_array(), len);
324
    memcpy(dest->after_gc_usage_array(), _last_gc_stat->after_gc_usage_array(), len);
325
  }
326
  return _last_gc_stat->gc_index();
327
}
328

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.