164 GCStatInfo::~GCStatInfo() { |
164 GCStatInfo::~GCStatInfo() { |
165 FREE_C_HEAP_ARRAY(MemoryUsage*, _before_gc_usage_array); |
165 FREE_C_HEAP_ARRAY(MemoryUsage*, _before_gc_usage_array); |
166 FREE_C_HEAP_ARRAY(MemoryUsage*, _after_gc_usage_array); |
166 FREE_C_HEAP_ARRAY(MemoryUsage*, _after_gc_usage_array); |
167 } |
167 } |
168 |
168 |
169 void GCStatInfo::copy_stat(GCStatInfo* stat) { |
|
170 set_index(stat->gc_index()); |
|
171 set_start_time(stat->start_time()); |
|
172 set_end_time(stat->end_time()); |
|
173 assert(_usage_array_size == stat->usage_array_size(), "Must have same array size"); |
|
174 for (int i = 0; i < _usage_array_size; i++) { |
|
175 set_before_gc_usage(i, stat->before_gc_usage_for_pool(i)); |
|
176 set_after_gc_usage(i, stat->after_gc_usage_for_pool(i)); |
|
177 } |
|
178 } |
|
179 |
|
180 void GCStatInfo::set_gc_usage(int pool_index, MemoryUsage usage, bool before_gc) { |
169 void GCStatInfo::set_gc_usage(int pool_index, MemoryUsage usage, bool before_gc) { |
181 MemoryUsage* gc_usage_array; |
170 MemoryUsage* gc_usage_array; |
182 if (before_gc) { |
171 if (before_gc) { |
183 gc_usage_array = _before_gc_usage_array; |
172 gc_usage_array = _before_gc_usage_array; |
184 } else { |
173 } else { |
185 gc_usage_array = _after_gc_usage_array; |
174 gc_usage_array = _after_gc_usage_array; |
186 } |
175 } |
187 gc_usage_array[pool_index] = usage; |
176 gc_usage_array[pool_index] = usage; |
188 } |
177 } |
189 |
178 |
|
179 void GCStatInfo::clear() { |
|
180 _index = 0; |
|
181 _start_time = 0L; |
|
182 _end_time = 0L; |
|
183 size_t len = _usage_array_size * sizeof(MemoryUsage); |
|
184 memset(_before_gc_usage_array, 0, len); |
|
185 memset(_after_gc_usage_array, 0, len); |
|
186 } |
|
187 |
|
188 |
190 GCMemoryManager::GCMemoryManager() : MemoryManager() { |
189 GCMemoryManager::GCMemoryManager() : MemoryManager() { |
191 _num_collections = 0; |
190 _num_collections = 0; |
192 _last_gc_stat = NULL; |
191 _last_gc_stat = NULL; |
|
192 _last_gc_lock = new Mutex(Mutex::leaf, "_last_gc_lock", true); |
|
193 _current_gc_stat = NULL; |
193 _num_gc_threads = 1; |
194 _num_gc_threads = 1; |
194 } |
195 } |
195 |
196 |
196 GCMemoryManager::~GCMemoryManager() { |
197 GCMemoryManager::~GCMemoryManager() { |
197 delete _last_gc_stat; |
198 delete _last_gc_stat; |
|
199 delete _last_gc_lock; |
|
200 delete _current_gc_stat; |
198 } |
201 } |
199 |
202 |
200 void GCMemoryManager::initialize_gc_stat_info() { |
203 void GCMemoryManager::initialize_gc_stat_info() { |
201 assert(MemoryService::num_memory_pools() > 0, "should have one or more memory pools"); |
204 assert(MemoryService::num_memory_pools() > 0, "should have one or more memory pools"); |
202 _last_gc_stat = new GCStatInfo(MemoryService::num_memory_pools()); |
205 _last_gc_stat = new GCStatInfo(MemoryService::num_memory_pools()); |
203 } |
206 _current_gc_stat = new GCStatInfo(MemoryService::num_memory_pools()); |
204 |
207 // tracking concurrent collections we need two objects: one to update, and one to |
205 void GCMemoryManager::gc_begin() { |
208 // hold the publicly available "last (completed) gc" information. |
206 assert(_last_gc_stat != NULL, "Just checking"); |
209 } |
207 _accumulated_timer.start(); |
210 |
208 _num_collections++; |
211 void GCMemoryManager::gc_begin(bool recordGCBeginTime, bool recordPreGCUsage, |
209 _last_gc_stat->set_index(_num_collections); |
212 bool recordAccumulatedGCTime) { |
210 _last_gc_stat->set_start_time(Management::timestamp()); |
213 assert(_last_gc_stat != NULL && _current_gc_stat != NULL, "Just checking"); |
211 |
214 if (recordAccumulatedGCTime) { |
212 // Keep memory usage of all memory pools |
215 _accumulated_timer.start(); |
213 for (int i = 0; i < MemoryService::num_memory_pools(); i++) { |
216 } |
214 MemoryPool* pool = MemoryService::get_memory_pool(i); |
217 // _num_collections now increases in gc_end, to count completed collections |
215 MemoryUsage usage = pool->get_memory_usage(); |
218 if (recordGCBeginTime) { |
216 _last_gc_stat->set_before_gc_usage(i, usage); |
219 _current_gc_stat->set_index(_num_collections+1); |
217 HS_DTRACE_PROBE8(hotspot, mem__pool__gc__begin, |
220 _current_gc_stat->set_start_time(Management::timestamp()); |
218 name(), strlen(name()), |
221 } |
219 pool->name(), strlen(pool->name()), |
222 |
220 usage.init_size(), usage.used(), |
223 if (recordPreGCUsage) { |
221 usage.committed(), usage.max_size()); |
224 // Keep memory usage of all memory pools |
222 } |
225 for (int i = 0; i < MemoryService::num_memory_pools(); i++) { |
223 } |
226 MemoryPool* pool = MemoryService::get_memory_pool(i); |
224 |
227 MemoryUsage usage = pool->get_memory_usage(); |
225 void GCMemoryManager::gc_end() { |
228 _current_gc_stat->set_before_gc_usage(i, usage); |
226 _accumulated_timer.stop(); |
229 HS_DTRACE_PROBE8(hotspot, mem__pool__gc__begin, |
227 _last_gc_stat->set_end_time(Management::timestamp()); |
230 name(), strlen(name()), |
228 |
231 pool->name(), strlen(pool->name()), |
229 int i; |
232 usage.init_size(), usage.used(), |
230 // keep the last gc statistics for all memory pools |
233 usage.committed(), usage.max_size()); |
231 for (i = 0; i < MemoryService::num_memory_pools(); i++) { |
234 } |
232 MemoryPool* pool = MemoryService::get_memory_pool(i); |
235 } |
233 MemoryUsage usage = pool->get_memory_usage(); |
236 } |
234 |
237 |
235 HS_DTRACE_PROBE8(hotspot, mem__pool__gc__end, |
238 // A collector MUST, even if it does not complete for some reason, |
236 name(), strlen(name()), |
239 // make a TraceMemoryManagerStats object where countCollection is true, |
237 pool->name(), strlen(pool->name()), |
240 // to ensure the current gc stat is placed in _last_gc_stat. |
238 usage.init_size(), usage.used(), |
241 void GCMemoryManager::gc_end(bool recordPostGCUsage, |
239 usage.committed(), usage.max_size()); |
242 bool recordAccumulatedGCTime, |
240 |
243 bool recordGCEndTime, bool countCollection) { |
241 _last_gc_stat->set_after_gc_usage(i, usage); |
244 if (recordAccumulatedGCTime) { |
242 } |
245 _accumulated_timer.stop(); |
243 |
246 } |
244 // Set last collection usage of the memory pools managed by this collector |
247 if (recordGCEndTime) { |
245 for (i = 0; i < num_memory_pools(); i++) { |
248 _current_gc_stat->set_end_time(Management::timestamp()); |
246 MemoryPool* pool = get_memory_pool(i); |
249 } |
247 MemoryUsage usage = pool->get_memory_usage(); |
250 |
248 |
251 if (recordPostGCUsage) { |
249 // Compare with GC usage threshold |
252 int i; |
250 pool->set_last_collection_usage(usage); |
253 // keep the last gc statistics for all memory pools |
251 LowMemoryDetector::detect_after_gc_memory(pool); |
254 for (i = 0; i < MemoryService::num_memory_pools(); i++) { |
252 } |
255 MemoryPool* pool = MemoryService::get_memory_pool(i); |
253 } |
256 MemoryUsage usage = pool->get_memory_usage(); |
|
257 |
|
258 HS_DTRACE_PROBE8(hotspot, mem__pool__gc__end, |
|
259 name(), strlen(name()), |
|
260 pool->name(), strlen(pool->name()), |
|
261 usage.init_size(), usage.used(), |
|
262 usage.committed(), usage.max_size()); |
|
263 |
|
264 _current_gc_stat->set_after_gc_usage(i, usage); |
|
265 } |
|
266 |
|
267 // Set last collection usage of the memory pools managed by this collector |
|
268 for (i = 0; i < num_memory_pools(); i++) { |
|
269 MemoryPool* pool = get_memory_pool(i); |
|
270 MemoryUsage usage = pool->get_memory_usage(); |
|
271 |
|
272 // Compare with GC usage threshold |
|
273 pool->set_last_collection_usage(usage); |
|
274 LowMemoryDetector::detect_after_gc_memory(pool); |
|
275 } |
|
276 } |
|
277 if (countCollection) { |
|
278 _num_collections++; |
|
279 // alternately update two objects making one public when complete |
|
280 { |
|
281 MutexLockerEx ml(_last_gc_lock, Mutex::_no_safepoint_check_flag); |
|
282 GCStatInfo *tmp = _last_gc_stat; |
|
283 _last_gc_stat = _current_gc_stat; |
|
284 _current_gc_stat = tmp; |
|
285 // reset the current stat for diagnosability purposes |
|
286 _current_gc_stat->clear(); |
|
287 } |
|
288 } |
|
289 } |
|
290 |
|
291 size_t GCMemoryManager::get_last_gc_stat(GCStatInfo* dest) { |
|
292 MutexLockerEx ml(_last_gc_lock, Mutex::_no_safepoint_check_flag); |
|
293 if (_last_gc_stat->gc_index() != 0) { |
|
294 dest->set_index(_last_gc_stat->gc_index()); |
|
295 dest->set_start_time(_last_gc_stat->start_time()); |
|
296 dest->set_end_time(_last_gc_stat->end_time()); |
|
297 assert(dest->usage_array_size() == _last_gc_stat->usage_array_size(), |
|
298 "Must have same array size"); |
|
299 size_t len = dest->usage_array_size() * sizeof(MemoryUsage); |
|
300 memcpy(dest->before_gc_usage_array(), _last_gc_stat->before_gc_usage_array(), len); |
|
301 memcpy(dest->after_gc_usage_array(), _last_gc_stat->after_gc_usage_array(), len); |
|
302 } |
|
303 return _last_gc_stat->gc_index(); |
|
304 } |