JDK-6651256 : jstack: DeleteGlobalRef method call doesn't lead to descreasing of global refs count shown by jstack
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: hs14,6u10,7,8u151
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2008-01-16
  • Updated: 2018-02-15
  • Resolved: 2014-01-23
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8 JDK 9
8u162Fixed 9 b03Fixed
Description
Test case:

1. Create a thread and measure a number of jni global refs shown by jstack
i.e. jstack output
	JNI global references: 629

2. Increase the jni global refs count by calling of NewGlobalRef method 1000 times
i.e. jstack output
	JNI global references: 1608

3. Decrease the jni global refs count by calling of DeleteGlobalRef method 1000 times
i.e. UNEXPECTED jstack output
	JNI global references: 1612

The behavior is the same for all platforms/configurations and may be not a jstack's bug.

To run existing test
1. ssh vmsqe-b2500-02.russia
2. cd /set/vmsqe/execution/results/adhoc/os161219_tmtools/2008-01-16_1/vm/SOLARIS-SPARC/client/mixed/vm-SOLARIS-SPARC_client_mixed_my.tmtools.testlist2008-01-16-19-52-33/ResultDir/globalrefcount/
3. sh rerun.sh

affected test
	tmtools/jstack/jniglobalref/globalrefcount

Comments
Uploaded my own testcase (test.tar.gz) for anyone who does not have the sqe test handy.
21-08-2017

--- a/src/share/vm/runtime/jniHandles.cpp Fri Dec 27 07:51:07 2013 -0800 +++ b/src/share/vm/runtime/jniHandles.cpp Thu Jan 23 10:05:21 2014 -0800 @@ -195,8 +195,10 @@ int _count; public: CountHandleClosure(): _count(0) {} - virtual void do_oop(oop* unused) { - _count++; + virtual void do_oop(oop* ooph) { + if (*ooph != JNIHandles::deleted_handle()) { + _count++; + } } virtual void do_oop(narrowOop* unused) { ShouldNotReachHere(); } int count() { return _count; }
23-01-2014

EVALUATION It seems to me that jniHandles.cpp sets the handle in the list of global refs to a special 'deleted_handle' value when DeleteGlobalRef is called. When NewGlobalRef is called, if there is no space for the new global ref, then a pass is made over the list and all entries with the 'deleted_handle' value are moved to a free list from which NewGlobalRefs are created. So, we have a question of semantics - should the jstack output labeled JNI Global References count the entries in the global ref list (whether they have been 'deleted' or not) or should it behave as if the count is incremented whenever NewGlobalRef is called and decremented whenever DeleteGlobalRef is called? It currently does the former. But I think the latter is more useful and what is intended, whicn means the code in JNIHandles::print_on that computes the count should be changed to not count entries which contain the special 'deleted_handle' value. Reassigning to runtime.
26-03-2008

EVALUATION Deleting a global ref just nulls the reference. You need a full GC for the reference to be released.
16-01-2008