-
Notifications
You must be signed in to change notification settings - Fork 6.2k
8256302: releasing oopStorage when deflating allows for faster deleting #11296
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
9313cb1
f260708
f0aad83
958c5e9
51310be
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -276,7 +276,10 @@ ObjectMonitor::ObjectMonitor(oop object) : | |
{ } | ||
|
||
ObjectMonitor::~ObjectMonitor() { | ||
_object.release(_oop_storage); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just to be clear, we can't call release here because not all There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now we use Update: s/(and safe)/(and presumed to be safe)/ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is confusing - why is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I look at it a little different, I guess. Here in the destructor we check if I don't check the current thread's state here nor do I assert it. Based There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay it was your "(and safe)" comment that implied to me that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I add a clarification to my comment above: Update: s/(and safe)/(and presumed to be safe)/ |
||
if (!_object.is_null()) { | ||
// Release object's oop storage if it hasn't already been done. | ||
release_object(); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In what case, would the object's oop storage not already been released? Is the destructor called here because of GC, where the object has been collected? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are a couple of places where thread-A allocates an ObjectMonitor for inflation, In an earlier version of the patch I had There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, thanks for the clarification. I agree with having it here in the destructor for that case. |
||
} | ||
|
||
oop ObjectMonitor::object() const { | ||
|
@@ -595,6 +598,9 @@ bool ObjectMonitor::deflate_monitor() { | |
install_displaced_markword_in_object(obj); | ||
} | ||
|
||
// Release object's oop storage since the ObjectMonitor has been deflated: | ||
release_object(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just to be clear, deflate_monitor() is called when a JavaThread is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I hope OopStorage.release() will assert if it's not safe. I think it does. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes it will assert() when it is called from a not safe context. |
||
|
||
// We leave owner == DEFLATER_MARKER and contentions < 0 | ||
// to force any racing threads to retry. | ||
return true; // Success, ObjectMonitor has been deflated. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1645,6 +1645,15 @@ class VM_RendezvousGCThreads : public VM_Operation { | |
}; | ||
}; | ||
|
||
static size_t delete_monitors(GrowableArray<ObjectMonitor*>* delete_list) { | ||
size_t count = 0; | ||
for (ObjectMonitor* monitor: *delete_list) { | ||
delete monitor; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just to be clear, this is the "delete monitor" call that is happening There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This comment doesn't make sense to me. We are calling release whilst blocked IIUC. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No we are not calling release while blocked. This function ( Since There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah that was the missing link. We delete deflated monitors and we release when deflating. |
||
count++; | ||
} | ||
return count; | ||
} | ||
|
||
// This function is called by the MonitorDeflationThread to deflate | ||
// ObjectMonitors. It is also called via do_final_audit_and_print_stats() | ||
// and VM_ThreadDump::doit() by the VMThread. | ||
|
@@ -1719,16 +1728,30 @@ size_t ObjectSynchronizer::deflate_idle_monitors(ObjectMonitorsHashtable* table) | |
} | ||
|
||
// After the handshake, safely free the ObjectMonitors that were | ||
// deflated in this cycle. | ||
for (ObjectMonitor* monitor: delete_list) { | ||
delete monitor; | ||
deleted_count++; | ||
|
||
if (current->is_Java_thread()) { | ||
// A JavaThread must check for a safepoint/handshake and honor it. | ||
chk_for_block_req(JavaThread::cast(current), "deletion", "deleted_count", | ||
deleted_count, ls, &timer); | ||
// deflated and unlinked in this cycle. | ||
if (current->is_Java_thread()) { | ||
if (ls != NULL) { | ||
timer.stop(); | ||
ls->print_cr("before setting blocked: unlinked_count=" SIZE_FORMAT | ||
", in_use_list stats: ceiling=" SIZE_FORMAT ", count=" | ||
SIZE_FORMAT ", max=" SIZE_FORMAT, | ||
unlinked_count, in_use_list_ceiling(), | ||
_in_use_list.count(), _in_use_list.max()); | ||
} | ||
// Mark the calling JavaThread blocked (safepoint safe) while we free | ||
// the ObjectMonitors so we don't delay safepoints whilst doing that. | ||
ThreadBlockInVM tbivm(JavaThread::cast(current)); | ||
if (ls != NULL) { | ||
ls->print_cr("after setting blocked: in_use_list stats: ceiling=" | ||
SIZE_FORMAT ", count=" SIZE_FORMAT ", max=" SIZE_FORMAT, | ||
in_use_list_ceiling(), _in_use_list.count(), _in_use_list.max()); | ||
timer.start(); | ||
} | ||
deleted_count = delete_monitors(&delete_list); | ||
// ThreadBlockInVM is destroyed here | ||
} else { | ||
// A non-JavaThread can just free the ObjectMonitors: | ||
deleted_count = delete_monitors(&delete_list); | ||
} | ||
assert(unlinked_count == deleted_count, "must be"); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would be a lot happier if WeakHandle.release() was non-const and set the _obj to nullptr, so that nothing can do this without release the weak handle.
This could be a follow-up RFE though since it affects other WeakHandle.release() calls.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to be clear, the weak handle is released, but the
_obj
field in the WeakHandle is notcleared so it is a dangling oop reference.
I didn't want to change
release(OopStorage* storage)
because that had a larger fan outof changes outside the scope of what I was trying to accomplish.