Mercurial > hg > truffle
annotate src/share/vm/runtime/jniHandles.cpp @ 1145:e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
Summary: Autonomic per-worker free block cache sizing, tunable coalition policies, fixes to per-size block statistics, retuned gain and bandwidth of some feedback loop filters to allow quicker reactivity to abrupt changes in ambient demand, and other heuristics to reduce fragmentation of the CMS old gen. Also tightened some assertions, including those related to locking.
Reviewed-by: jmasa
author | ysr |
---|---|
date | Wed, 23 Dec 2009 09:23:54 -0800 |
parents | d1605aabd0a1 |
children | 4ce7240d622c |
rev | line source |
---|---|
0 | 1 /* |
196 | 2 * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. |
0 | 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | |
20 * CA 95054 USA or visit www.sun.com if you need additional information or | |
21 * have any questions. | |
22 * | |
23 */ | |
24 | |
25 # include "incls/_precompiled.incl" | |
26 # include "incls/_jniHandles.cpp.incl" | |
27 | |
28 | |
29 JNIHandleBlock* JNIHandles::_global_handles = NULL; | |
30 JNIHandleBlock* JNIHandles::_weak_global_handles = NULL; | |
31 oop JNIHandles::_deleted_handle = NULL; | |
32 | |
33 | |
34 jobject JNIHandles::make_local(oop obj) { | |
35 if (obj == NULL) { | |
36 return NULL; // ignore null handles | |
37 } else { | |
38 Thread* thread = Thread::current(); | |
39 assert(Universe::heap()->is_in_reserved(obj), "sanity check"); | |
40 return thread->active_handles()->allocate_handle(obj); | |
41 } | |
42 } | |
43 | |
44 | |
45 // optimized versions | |
46 | |
47 jobject JNIHandles::make_local(Thread* thread, oop obj) { | |
48 if (obj == NULL) { | |
49 return NULL; // ignore null handles | |
50 } else { | |
51 assert(Universe::heap()->is_in_reserved(obj), "sanity check"); | |
52 return thread->active_handles()->allocate_handle(obj); | |
53 } | |
54 } | |
55 | |
56 | |
57 jobject JNIHandles::make_local(JNIEnv* env, oop obj) { | |
58 if (obj == NULL) { | |
59 return NULL; // ignore null handles | |
60 } else { | |
61 JavaThread* thread = JavaThread::thread_from_jni_environment(env); | |
62 assert(Universe::heap()->is_in_reserved(obj), "sanity check"); | |
63 return thread->active_handles()->allocate_handle(obj); | |
64 } | |
65 } | |
66 | |
67 | |
68 jobject JNIHandles::make_global(Handle obj) { | |
69 jobject res = NULL; | |
70 if (!obj.is_null()) { | |
71 // ignore null handles | |
72 MutexLocker ml(JNIGlobalHandle_lock); | |
73 assert(Universe::heap()->is_in_reserved(obj()), "sanity check"); | |
74 res = _global_handles->allocate_handle(obj()); | |
75 } else { | |
76 CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops()); | |
77 } | |
78 | |
79 return res; | |
80 } | |
81 | |
82 | |
83 jobject JNIHandles::make_weak_global(Handle obj) { | |
84 jobject res = NULL; | |
85 if (!obj.is_null()) { | |
86 // ignore null handles | |
87 MutexLocker ml(JNIGlobalHandle_lock); | |
88 assert(Universe::heap()->is_in_reserved(obj()), "sanity check"); | |
89 res = _weak_global_handles->allocate_handle(obj()); | |
90 } else { | |
91 CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops()); | |
92 } | |
93 return res; | |
94 } | |
95 | |
96 jmethodID JNIHandles::make_jmethod_id(methodHandle mh) { | |
97 return (jmethodID) make_weak_global(mh); | |
98 } | |
99 | |
100 | |
101 | |
102 void JNIHandles::change_method_associated_with_jmethod_id(jmethodID jmid, methodHandle mh) { | |
103 MutexLocker ml(JNIGlobalHandle_lock); // Is this necessary? | |
104 Handle obj = (Handle)mh; | |
105 oop* jobj = (oop*)jmid; | |
106 *jobj = obj(); | |
107 } | |
108 | |
109 | |
110 void JNIHandles::destroy_global(jobject handle) { | |
111 if (handle != NULL) { | |
112 assert(is_global_handle(handle), "Invalid delete of global JNI handle"); | |
113 *((oop*)handle) = deleted_handle(); // Mark the handle as deleted, allocate will reuse it | |
114 } | |
115 } | |
116 | |
117 | |
118 void JNIHandles::destroy_weak_global(jobject handle) { | |
119 if (handle != NULL) { | |
120 assert(!CheckJNICalls || is_weak_global_handle(handle), "Invalid delete of weak global JNI handle"); | |
121 *((oop*)handle) = deleted_handle(); // Mark the handle as deleted, allocate will reuse it | |
122 } | |
123 } | |
124 | |
125 void JNIHandles::destroy_jmethod_id(jmethodID mid) { | |
126 destroy_weak_global((jobject)mid); | |
127 } | |
128 | |
129 | |
130 void JNIHandles::oops_do(OopClosure* f) { | |
131 f->do_oop(&_deleted_handle); | |
132 _global_handles->oops_do(f); | |
133 } | |
134 | |
135 | |
136 void JNIHandles::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f) { | |
137 _weak_global_handles->weak_oops_do(is_alive, f); | |
138 } | |
139 | |
140 | |
141 void JNIHandles::initialize() { | |
142 _global_handles = JNIHandleBlock::allocate_block(); | |
143 _weak_global_handles = JNIHandleBlock::allocate_block(); | |
144 EXCEPTION_MARK; | |
145 // We will never reach the CATCH below since Exceptions::_throw will cause | |
146 // the VM to exit if an exception is thrown during initialization | |
147 klassOop k = SystemDictionary::object_klass(); | |
148 _deleted_handle = instanceKlass::cast(k)->allocate_permanent_instance(CATCH); | |
149 } | |
150 | |
151 | |
152 bool JNIHandles::is_local_handle(Thread* thread, jobject handle) { | |
153 JNIHandleBlock* block = thread->active_handles(); | |
154 | |
155 // Look back past possible native calls to jni_PushLocalFrame. | |
156 while (block != NULL) { | |
157 if (block->chain_contains(handle)) { | |
158 return true; | |
159 } | |
160 block = block->pop_frame_link(); | |
161 } | |
162 return false; | |
163 } | |
164 | |
165 | |
166 // Determine if the handle is somewhere in the current thread's stack. | |
167 // We easily can't isolate any particular stack frame the handle might | |
168 // come from, so we'll check the whole stack. | |
169 | |
170 bool JNIHandles::is_frame_handle(JavaThread* thr, jobject obj) { | |
171 // If there is no java frame, then this must be top level code, such | |
172 // as the java command executable, in which case, this type of handle | |
173 // is not permitted. | |
174 return (thr->has_last_Java_frame() && | |
175 (void*)obj < (void*)thr->stack_base() && | |
176 (void*)obj >= (void*)thr->last_Java_sp()); | |
177 } | |
178 | |
179 | |
180 bool JNIHandles::is_global_handle(jobject handle) { | |
181 return _global_handles->chain_contains(handle); | |
182 } | |
183 | |
184 | |
185 bool JNIHandles::is_weak_global_handle(jobject handle) { | |
186 return _weak_global_handles->chain_contains(handle); | |
187 } | |
188 | |
189 long JNIHandles::global_handle_memory_usage() { | |
190 return _global_handles->memory_usage(); | |
191 } | |
192 | |
193 long JNIHandles::weak_global_handle_memory_usage() { | |
194 return _weak_global_handles->memory_usage(); | |
195 } | |
196 | |
197 | |
198 class AlwaysAliveClosure: public BoolObjectClosure { | |
199 public: | |
200 bool do_object_b(oop obj) { return true; } | |
201 void do_object(oop obj) { assert(false, "Don't call"); } | |
202 }; | |
203 | |
204 class CountHandleClosure: public OopClosure { | |
205 private: | |
206 int _count; | |
207 public: | |
208 CountHandleClosure(): _count(0) {} | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
209 virtual void do_oop(oop* unused) { |
0 | 210 _count++; |
211 } | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
212 virtual void do_oop(narrowOop* unused) { ShouldNotReachHere(); } |
0 | 213 int count() { return _count; } |
214 }; | |
215 | |
216 // We assume this is called at a safepoint: no lock is needed. | |
217 void JNIHandles::print_on(outputStream* st) { | |
218 assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); | |
219 assert(_global_handles != NULL && _weak_global_handles != NULL, | |
220 "JNIHandles not initialized"); | |
221 | |
222 CountHandleClosure global_handle_count; | |
223 AlwaysAliveClosure always_alive; | |
224 oops_do(&global_handle_count); | |
225 weak_oops_do(&always_alive, &global_handle_count); | |
226 | |
227 st->print_cr("JNI global references: %d", global_handle_count.count()); | |
228 st->cr(); | |
229 st->flush(); | |
230 } | |
231 | |
232 class VerifyHandleClosure: public OopClosure { | |
233 public: | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
234 virtual void do_oop(oop* root) { |
0 | 235 (*root)->verify(); |
236 } | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
237 virtual void do_oop(narrowOop* root) { ShouldNotReachHere(); } |
0 | 238 }; |
239 | |
240 void JNIHandles::verify() { | |
241 VerifyHandleClosure verify_handle; | |
242 AlwaysAliveClosure always_alive; | |
243 | |
244 oops_do(&verify_handle); | |
245 weak_oops_do(&always_alive, &verify_handle); | |
246 } | |
247 | |
248 | |
249 | |
250 void jni_handles_init() { | |
251 JNIHandles::initialize(); | |
252 } | |
253 | |
254 | |
255 int JNIHandleBlock::_blocks_allocated = 0; | |
256 JNIHandleBlock* JNIHandleBlock::_block_free_list = NULL; | |
257 #ifndef PRODUCT | |
258 JNIHandleBlock* JNIHandleBlock::_block_list = NULL; | |
259 #endif | |
260 | |
261 | |
262 void JNIHandleBlock::zap() { | |
263 // Zap block values | |
264 _top = 0; | |
265 for (int index = 0; index < block_size_in_oops; index++) { | |
266 _handles[index] = badJNIHandle; | |
267 } | |
268 } | |
269 | |
270 JNIHandleBlock* JNIHandleBlock::allocate_block(Thread* thread) { | |
271 assert(thread == NULL || thread == Thread::current(), "sanity check"); | |
272 JNIHandleBlock* block; | |
273 // Check the thread-local free list for a block so we don't | |
274 // have to acquire a mutex. | |
275 if (thread != NULL && thread->free_handle_block() != NULL) { | |
276 block = thread->free_handle_block(); | |
277 thread->set_free_handle_block(block->_next); | |
278 } | |
279 else { | |
280 // locking with safepoint checking introduces a potential deadlock: | |
281 // - we would hold JNIHandleBlockFreeList_lock and then Threads_lock | |
282 // - another would hold Threads_lock (jni_AttachCurrentThread) and then | |
283 // JNIHandleBlockFreeList_lock (JNIHandleBlock::allocate_block) | |
284 MutexLockerEx ml(JNIHandleBlockFreeList_lock, | |
285 Mutex::_no_safepoint_check_flag); | |
286 if (_block_free_list == NULL) { | |
287 // Allocate new block | |
288 block = new JNIHandleBlock(); | |
289 _blocks_allocated++; | |
290 if (TraceJNIHandleAllocation) { | |
291 tty->print_cr("JNIHandleBlock " INTPTR_FORMAT " allocated (%d total blocks)", | |
292 block, _blocks_allocated); | |
293 } | |
294 if (ZapJNIHandleArea) block->zap(); | |
295 #ifndef PRODUCT | |
296 // Link new block to list of all allocated blocks | |
297 block->_block_list_link = _block_list; | |
298 _block_list = block; | |
299 #endif | |
300 } else { | |
301 // Get block from free list | |
302 block = _block_free_list; | |
303 _block_free_list = _block_free_list->_next; | |
304 } | |
305 } | |
306 block->_top = 0; | |
307 block->_next = NULL; | |
308 block->_pop_frame_link = NULL; | |
309 // _last, _free_list & _allocate_before_rebuild initialized in allocate_handle | |
310 debug_only(block->_last = NULL); | |
311 debug_only(block->_free_list = NULL); | |
312 debug_only(block->_allocate_before_rebuild = -1); | |
313 return block; | |
314 } | |
315 | |
316 | |
317 void JNIHandleBlock::release_block(JNIHandleBlock* block, Thread* thread) { | |
318 assert(thread == NULL || thread == Thread::current(), "sanity check"); | |
319 JNIHandleBlock* pop_frame_link = block->pop_frame_link(); | |
320 // Put returned block at the beginning of the thread-local free list. | |
321 // Note that if thread == NULL, we use it as an implicit argument that | |
322 // we _don't_ want the block to be kept on the free_handle_block. | |
323 // See for instance JavaThread::exit(). | |
324 if (thread != NULL ) { | |
325 if (ZapJNIHandleArea) block->zap(); | |
326 JNIHandleBlock* freelist = thread->free_handle_block(); | |
327 block->_pop_frame_link = NULL; | |
328 thread->set_free_handle_block(block); | |
329 | |
330 // Add original freelist to end of chain | |
331 if ( freelist != NULL ) { | |
332 while ( block->_next != NULL ) block = block->_next; | |
333 block->_next = freelist; | |
334 } | |
335 block = NULL; | |
336 } | |
337 if (block != NULL) { | |
338 // Return blocks to free list | |
339 // locking with safepoint checking introduces a potential deadlock: | |
340 // - we would hold JNIHandleBlockFreeList_lock and then Threads_lock | |
341 // - another would hold Threads_lock (jni_AttachCurrentThread) and then | |
342 // JNIHandleBlockFreeList_lock (JNIHandleBlock::allocate_block) | |
343 MutexLockerEx ml(JNIHandleBlockFreeList_lock, | |
344 Mutex::_no_safepoint_check_flag); | |
345 while (block != NULL) { | |
346 if (ZapJNIHandleArea) block->zap(); | |
347 JNIHandleBlock* next = block->_next; | |
348 block->_next = _block_free_list; | |
349 _block_free_list = block; | |
350 block = next; | |
351 } | |
352 } | |
353 if (pop_frame_link != NULL) { | |
354 // As a sanity check we release blocks pointed to by the pop_frame_link. | |
355 // This should never happen (only if PopLocalFrame is not called the | |
356 // correct number of times). | |
357 release_block(pop_frame_link, thread); | |
358 } | |
359 } | |
360 | |
361 | |
362 void JNIHandleBlock::oops_do(OopClosure* f) { | |
363 JNIHandleBlock* current_chain = this; | |
364 // Iterate over chain of blocks, followed by chains linked through the | |
365 // pop frame links. | |
366 while (current_chain != NULL) { | |
367 for (JNIHandleBlock* current = current_chain; current != NULL; | |
368 current = current->_next) { | |
369 assert(current == current_chain || current->pop_frame_link() == NULL, | |
370 "only blocks first in chain should have pop frame link set"); | |
371 for (int index = 0; index < current->_top; index++) { | |
372 oop* root = &(current->_handles)[index]; | |
373 oop value = *root; | |
374 // traverse heap pointers only, not deleted handles or free list | |
375 // pointers | |
376 if (value != NULL && Universe::heap()->is_in_reserved(value)) { | |
377 f->do_oop(root); | |
378 } | |
379 } | |
380 // the next handle block is valid only if current block is full | |
381 if (current->_top < block_size_in_oops) { | |
382 break; | |
383 } | |
384 } | |
385 current_chain = current_chain->pop_frame_link(); | |
386 } | |
387 } | |
388 | |
389 | |
390 void JNIHandleBlock::weak_oops_do(BoolObjectClosure* is_alive, | |
391 OopClosure* f) { | |
392 for (JNIHandleBlock* current = this; current != NULL; current = current->_next) { | |
393 assert(current->pop_frame_link() == NULL, | |
394 "blocks holding weak global JNI handles should not have pop frame link set"); | |
395 for (int index = 0; index < current->_top; index++) { | |
396 oop* root = &(current->_handles)[index]; | |
397 oop value = *root; | |
398 // traverse heap pointers only, not deleted handles or free list pointers | |
399 if (value != NULL && Universe::heap()->is_in_reserved(value)) { | |
400 if (is_alive->do_object_b(value)) { | |
401 // The weakly referenced object is alive, update pointer | |
402 f->do_oop(root); | |
403 } else { | |
404 // The weakly referenced object is not alive, clear the reference by storing NULL | |
405 if (TraceReferenceGC) { | |
406 tty->print_cr("Clearing JNI weak reference (" INTPTR_FORMAT ")", root); | |
407 } | |
408 *root = NULL; | |
409 } | |
410 } | |
411 } | |
412 // the next handle block is valid only if current block is full | |
413 if (current->_top < block_size_in_oops) { | |
414 break; | |
415 } | |
416 } | |
417 } | |
418 | |
419 | |
420 jobject JNIHandleBlock::allocate_handle(oop obj) { | |
421 assert(Universe::heap()->is_in_reserved(obj), "sanity check"); | |
422 if (_top == 0) { | |
423 // This is the first allocation or the initial block got zapped when | |
424 // entering a native function. If we have any following blocks they are | |
425 // not valid anymore. | |
426 for (JNIHandleBlock* current = _next; current != NULL; | |
427 current = current->_next) { | |
428 assert(current->_last == NULL, "only first block should have _last set"); | |
429 assert(current->_free_list == NULL, | |
430 "only first block should have _free_list set"); | |
431 current->_top = 0; | |
432 if (ZapJNIHandleArea) current->zap(); | |
433 } | |
434 // Clear initial block | |
435 _free_list = NULL; | |
436 _allocate_before_rebuild = 0; | |
437 _last = this; | |
438 if (ZapJNIHandleArea) zap(); | |
439 } | |
440 | |
441 // Try last block | |
442 if (_last->_top < block_size_in_oops) { | |
443 oop* handle = &(_last->_handles)[_last->_top++]; | |
444 *handle = obj; | |
445 return (jobject) handle; | |
446 } | |
447 | |
448 // Try free list | |
449 if (_free_list != NULL) { | |
450 oop* handle = _free_list; | |
451 _free_list = (oop*) *_free_list; | |
452 *handle = obj; | |
453 return (jobject) handle; | |
454 } | |
455 // Check if unused block follow last | |
456 if (_last->_next != NULL) { | |
457 // update last and retry | |
458 _last = _last->_next; | |
459 return allocate_handle(obj); | |
460 } | |
461 | |
462 // No space available, we have to rebuild free list or expand | |
463 if (_allocate_before_rebuild == 0) { | |
464 rebuild_free_list(); // updates _allocate_before_rebuild counter | |
465 } else { | |
466 // Append new block | |
467 Thread* thread = Thread::current(); | |
468 Handle obj_handle(thread, obj); | |
469 // This can block, so we need to preserve obj accross call. | |
470 _last->_next = JNIHandleBlock::allocate_block(thread); | |
471 _last = _last->_next; | |
472 _allocate_before_rebuild--; | |
473 obj = obj_handle(); | |
474 } | |
475 return allocate_handle(obj); // retry | |
476 } | |
477 | |
478 | |
479 void JNIHandleBlock::rebuild_free_list() { | |
480 assert(_allocate_before_rebuild == 0 && _free_list == NULL, "just checking"); | |
481 int free = 0; | |
482 int blocks = 0; | |
483 for (JNIHandleBlock* current = this; current != NULL; current = current->_next) { | |
484 for (int index = 0; index < current->_top; index++) { | |
485 oop* handle = &(current->_handles)[index]; | |
486 if (*handle == JNIHandles::deleted_handle()) { | |
487 // this handle was cleared out by a delete call, reuse it | |
488 *handle = (oop) _free_list; | |
489 _free_list = handle; | |
490 free++; | |
491 } | |
492 } | |
493 // we should not rebuild free list if there are unused handles at the end | |
494 assert(current->_top == block_size_in_oops, "just checking"); | |
495 blocks++; | |
496 } | |
497 // Heuristic: if more than half of the handles are free we rebuild next time | |
498 // as well, otherwise we append a corresponding number of new blocks before | |
499 // attempting a free list rebuild again. | |
500 int total = blocks * block_size_in_oops; | |
501 int extra = total - 2*free; | |
502 if (extra > 0) { | |
503 // Not as many free handles as we would like - compute number of new blocks to append | |
504 _allocate_before_rebuild = (extra + block_size_in_oops - 1) / block_size_in_oops; | |
505 } | |
506 if (TraceJNIHandleAllocation) { | |
507 tty->print_cr("Rebuild free list JNIHandleBlock " INTPTR_FORMAT " blocks=%d used=%d free=%d add=%d", | |
508 this, blocks, total-free, free, _allocate_before_rebuild); | |
509 } | |
510 } | |
511 | |
512 | |
513 bool JNIHandleBlock::contains(jobject handle) const { | |
514 return ((jobject)&_handles[0] <= handle && handle<(jobject)&_handles[_top]); | |
515 } | |
516 | |
517 | |
518 bool JNIHandleBlock::chain_contains(jobject handle) const { | |
519 for (JNIHandleBlock* current = (JNIHandleBlock*) this; current != NULL; current = current->_next) { | |
520 if (current->contains(handle)) { | |
521 return true; | |
522 } | |
523 } | |
524 return false; | |
525 } | |
526 | |
527 | |
528 int JNIHandleBlock::length() const { | |
529 int result = 1; | |
530 for (JNIHandleBlock* current = _next; current != NULL; current = current->_next) { | |
531 result++; | |
532 } | |
533 return result; | |
534 } | |
535 | |
536 // This method is not thread-safe, i.e., must be called whule holding a lock on the | |
537 // structure. | |
538 long JNIHandleBlock::memory_usage() const { | |
539 return length() * sizeof(JNIHandleBlock); | |
540 } | |
541 | |
542 | |
543 #ifndef PRODUCT | |
544 | |
545 bool JNIHandleBlock::any_contains(jobject handle) { | |
546 for (JNIHandleBlock* current = _block_list; current != NULL; current = current->_block_list_link) { | |
547 if (current->contains(handle)) { | |
548 return true; | |
549 } | |
550 } | |
551 return false; | |
552 } | |
553 | |
554 void JNIHandleBlock::print_statistics() { | |
555 int used_blocks = 0; | |
556 int free_blocks = 0; | |
557 int used_handles = 0; | |
558 int free_handles = 0; | |
559 JNIHandleBlock* block = _block_list; | |
560 while (block != NULL) { | |
561 if (block->_top > 0) { | |
562 used_blocks++; | |
563 } else { | |
564 free_blocks++; | |
565 } | |
566 used_handles += block->_top; | |
567 free_handles += (block_size_in_oops - block->_top); | |
568 block = block->_block_list_link; | |
569 } | |
570 tty->print_cr("JNIHandleBlocks statistics"); | |
571 tty->print_cr("- blocks allocated: %d", used_blocks + free_blocks); | |
572 tty->print_cr("- blocks in use: %d", used_blocks); | |
573 tty->print_cr("- blocks free: %d", free_blocks); | |
574 tty->print_cr("- handles in use: %d", used_handles); | |
575 tty->print_cr("- handles free: %d", free_handles); | |
576 } | |
577 | |
578 #endif |