Currently, OopHandle::release() is implemented as follows:
inline void OopHandle::release(OopStorage* storage) {
if (peek() != NULL) {
// Clear the OopHandle first
NativeAccess<>::oop_store(_obj, (oop)NULL);
storage->release(_obj);
}
}
However, peek() returns NULL not only if the oop* `_obj` is NULL, but also when `_obj` points to a zero oop. In the latter case, the oop* `_obj` will not be released from the corresponding OopStorage and the slot it occupies will remain alive forever.
This behavior can be easily triggered with the attached LeakTestMinimal.java test (thanks to Oli Gillespie from the Amazon Profiler team for detecting the issue and providing a reproducer).
The fix is trivial:
diff --git a/src/hotspot/share/oops/oopHandle.inline.hpp b/src/hotspot/share/oops/oopHandle.inline.hpp
index 44362499a2c..20de5146ec3 100644
--- a/src/hotspot/share/oops/oopHandle.inline.hpp
+++ b/src/hotspot/share/oops/oopHandle.inline.hpp
@@ -48,7 +48,7 @@ inline OopHandle::OopHandle(OopStorage* storage, oop obj) :
}
inline void OopHandle::release(OopStorage* storage) {
- if (peek() != NULL) {
+ if (_obj != NULL) {
// Clear the OopHandle first
NativeAccess<>::oop_store(_obj, (oop)NULL);
storage->release(_obj);