31
31
32
32
ShenandoahUncommitThread::ShenandoahUncommitThread (ShenandoahHeap* heap)
33
33
: _heap(heap),
34
- _stop_lock(Mutex::safepoint - 2 , " ShenandoahUncommitStop_lock" , true ),
35
- _uncommit_lock(Mutex::safepoint - 2 , " ShenandoahUncommitCancel_lock" , true ) {
34
+ _uncommit_lock(Mutex::safepoint - 2 , " ShenandoahUncommit_lock" , true ) {
36
35
set_name (" Shenandoah Uncommit Thread" );
37
36
create_and_start ();
38
37
@@ -68,11 +67,10 @@ void ShenandoahUncommitThread::run_service() {
68
67
uncommit (shrink_before, shrink_until);
69
68
}
70
69
}
71
- {
72
- MonitorLocker locker (&_stop_lock, Mutex::_no_safepoint_check_flag);
73
- if (!_stop_requested.is_set ()) {
74
- timed_out = locker.wait (poll_interval);
75
- }
70
+
71
+ if (!should_terminate ()) {
72
+ MonitorLocker locker (&_uncommit_lock, Mutex::_no_safepoint_check_flag);
73
+ timed_out = locker.wait (poll_interval);
76
74
}
77
75
}
78
76
}
@@ -104,15 +102,15 @@ bool ShenandoahUncommitThread::has_work(double shrink_before, size_t shrink_unti
104
102
void ShenandoahUncommitThread::notify_soft_max_changed () {
105
103
assert (is_uncommit_allowed (), " Only notify if uncommit is allowed" );
106
104
if (_soft_max_changed.try_set ()) {
107
- MonitorLocker locker (&_stop_lock , Mutex::_no_safepoint_check_flag);
105
+ MonitorLocker locker (&_uncommit_lock , Mutex::_no_safepoint_check_flag);
108
106
locker.notify_all ();
109
107
}
110
108
}
111
109
112
110
void ShenandoahUncommitThread::notify_explicit_gc_requested () {
113
111
assert (is_uncommit_allowed (), " Only notify if uncommit is allowed" );
114
112
if (_explicit_gc_requested.try_set ()) {
115
- MonitorLocker locker (&_stop_lock , Mutex::_no_safepoint_check_flag);
113
+ MonitorLocker locker (&_uncommit_lock , Mutex::_no_safepoint_check_flag);
116
114
locker.notify_all ();
117
115
}
118
116
}
@@ -125,33 +123,64 @@ void ShenandoahUncommitThread::uncommit(double shrink_before, size_t shrink_unti
125
123
assert (ShenandoahUncommit, " should be enabled" );
126
124
assert (_uncommit_in_progress.is_unset (), " Uncommit should not be in progress" );
127
125
128
- if (!is_uncommit_allowed ()) {
126
+ {
127
+ // Final check, under the lock, if uncommit is allowed.
128
+ MonitorLocker locker (&_uncommit_lock, Mutex::_no_safepoint_check_flag);
129
+ if (is_uncommit_allowed ()) {
130
+ _uncommit_in_progress.set ();
131
+ }
132
+ }
133
+
134
+ // If not allowed to start, do nothing.
135
+ if (!_uncommit_in_progress.is_set ()) {
129
136
return ;
130
137
}
131
138
139
+ // From here on, uncommit is in progress. Attempts to stop the uncommit must wait
140
+ // until the cancellation request is acknowledged and uncommit is no longer in progress.
132
141
const char * msg = " Concurrent uncommit" ;
142
+ const double start = os::elapsedTime ();
133
143
EventMark em (" %s" , msg);
134
- double start = os::elapsedTime ();
135
144
log_info (gc, start)(" %s" , msg);
136
145
137
- _uncommit_in_progress.set ();
146
+ // This is the number of regions uncommitted during this increment of uncommit work.
147
+ const size_t uncommitted_region_count = do_uncommit_work (shrink_before, shrink_until);
148
+
149
+ {
150
+ MonitorLocker locker (&_uncommit_lock, Mutex::_no_safepoint_check_flag);
151
+ _uncommit_in_progress.unset ();
152
+ locker.notify_all ();
153
+ }
138
154
155
+ if (uncommitted_region_count > 0 ) {
156
+ _heap->notify_heap_changed ();
157
+ }
158
+
159
+ const double elapsed = os::elapsedTime () - start;
160
+ log_info (gc)(" %s " PROPERFMT " (" PROPERFMT " ) %.3fms" ,
161
+ msg, PROPERFMTARGS (uncommitted_region_count * ShenandoahHeapRegion::region_size_bytes ()), PROPERFMTARGS (_heap->capacity ()),
162
+ elapsed * MILLIUNITS);
163
+ }
164
+
165
+ size_t ShenandoahUncommitThread::do_uncommit_work (double shrink_before, size_t shrink_until) const {
166
+ size_t count = 0 ;
139
167
// Application allocates from the beginning of the heap, and GC allocates at
140
168
// the end of it. It is more efficient to uncommit from the end, so that applications
141
169
// could enjoy the near committed regions. GC allocations are much less frequent,
142
170
// and therefore can accept the committing costs.
143
- size_t count = 0 ;
144
171
for (size_t i = _heap->num_regions (); i > 0 ; i--) {
145
172
if (!is_uncommit_allowed ()) {
173
+ // GC wants to start, so the uncommit operation must stop
146
174
break ;
147
175
}
148
176
149
177
ShenandoahHeapRegion* r = _heap->get_region (i - 1 );
150
178
if (r->is_empty_committed () && (r->empty_time () < shrink_before)) {
151
179
SuspendibleThreadSetJoiner sts_joiner;
152
- ShenandoahHeapLocker locker (_heap->lock ());
180
+ ShenandoahHeapLocker heap_locker (_heap->lock ());
153
181
if (r->is_empty_committed ()) {
154
182
if (_heap->committed () < shrink_until + ShenandoahHeapRegion::region_size_bytes ()) {
183
+ // We have uncommitted enough regions to hit the target heap committed size
155
184
break ;
156
185
}
157
186
@@ -161,26 +190,13 @@ void ShenandoahUncommitThread::uncommit(double shrink_before, size_t shrink_unti
161
190
}
162
191
SpinPause (); // allow allocators to take the lock
163
192
}
164
-
165
- {
166
- MonitorLocker locker (&_uncommit_lock, Mutex::_no_safepoint_check_flag);
167
- _uncommit_in_progress.unset ();
168
- locker.notify_all ();
169
- }
170
-
171
- if (count > 0 ) {
172
- _heap->notify_heap_changed ();
173
- }
174
-
175
- double elapsed = os::elapsedTime () - start;
176
- log_info (gc)(" %s " PROPERFMT " (" PROPERFMT " ) %.3fms" ,
177
- msg, PROPERFMTARGS (count * ShenandoahHeapRegion::region_size_bytes ()), PROPERFMTARGS (_heap->capacity ()),
178
- elapsed * MILLIUNITS);
193
+ return count;
179
194
}
180
195
196
+
181
197
void ShenandoahUncommitThread::stop_service () {
182
- MonitorLocker locker (&_stop_lock , Mutex::_safepoint_check_flag);
183
- _stop_requested. set ();
198
+ MonitorLocker locker (&_uncommit_lock , Mutex::_safepoint_check_flag);
199
+ _uncommit_allowed. unset ();
184
200
locker.notify_all ();
185
201
}
186
202
@@ -193,5 +209,6 @@ void ShenandoahUncommitThread::forbid_uncommit() {
193
209
}
194
210
195
211
void ShenandoahUncommitThread::allow_uncommit () {
212
+ MonitorLocker locker (&_uncommit_lock, Mutex::_no_safepoint_check_flag);
196
213
_uncommit_allowed.set ();
197
214
}
0 commit comments