/* * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. * */ #include "gc/g1/g1ConcurrentHeapResize.hpp" #include "gc/g1/g1ConcurrentHeapResizeThread.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/heapRegionManager.inline.hpp" G1ConcurrentHeapResize::G1ConcurrentHeapResize(G1CollectedHeap* g1h, HeapRegionManager* hrm) : _g1h(g1h), _hrm(hrm), _completed_initialization(false) { // Create & start ConcurrentHeapResize thread _resize_thread = new G1ConcurrentHeapResizeThread(this); if (_resize_thread->osthread() == NULL) { vm_shutdown_during_initialization("Could not create ConcurrentHeapResizeThread"); } _completed_initialization = true; } void G1ConcurrentHeapResize::shrink(size_t shrink_bytes) { assert_at_safepoint_on_vm_thread(); assert(resize_thread()->idle(), "sanity"); log_debug(gc, ergo, heap)("Shrink the heap in concurrent. shrinking amount: " SIZE_FORMAT "B", shrink_bytes); uint num_regions_to_remove = (uint)(shrink_bytes / HeapRegion::GrainBytes); _hrm->prepare_concurrent_uncommit_regions(num_regions_to_remove); trigger_concurrent_work(); } void G1ConcurrentHeapResize::trigger_concurrent_work() { assert(has_regions_for_concurrent_processing(), "sanity"); { MutexLocker x(resize_thread()->start_monitor(), Mutex::_no_safepoint_check_flag); resize_thread()->set_working(); resize_thread()->start_monitor()->notify(); } } #ifndef PRODUCT bool G1ConcurrentHeapResize::has_regions_for_concurrent_processing() { return _hrm->num_of_concurrent_resizing_regions() != 0; } #endif void G1ConcurrentHeapResize::do_work() { assert(Thread::current() == resize_thread(), "must be G1ConcurrentHeapResizeThread"); _hrm->concurrent_uncommit_regions(); } void G1ConcurrentHeapResize::notify_work_done() { assert(Thread::current() == resize_thread(), "must be G1ConcurrentHeapResizeThread"); { MutexLocker x(resize_thread()->done_monitor(), Mutex::_no_safepoint_check_flag); resize_thread()->set_done(); resize_thread()->done_monitor()->notify(); } } void G1ConcurrentHeapResize::check_concurrent_work_finish() { assert_at_safepoint_on_vm_thread(); if (resize_thread()->working()) { // The concurrent work is still in progress return; } if (resize_thread()->done()) { finish_concurrent_resizing(); } else { assert(!has_regions_for_concurrent_processing(), "sanity"); } } void G1ConcurrentHeapResize::finish_concurrent_resizing() { assert(has_regions_for_concurrent_processing(), "sanity"); _hrm->synchronize_concurrent_resizing_regions(); resize_thread()->set_idle(); } void G1ConcurrentHeapResize::wait_for_concurrent_work_finish() { assert_at_safepoint_on_vm_thread(); if (resize_thread()->idle()) { // No concurrent work assert(!has_regions_for_concurrent_processing(), "sanity"); return; } if (!resize_thread()->done()) { MonitorLocker ml(resize_thread()->done_monitor(), Mutex::_no_safepoint_check_flag); while (!resize_thread()->done()) { ml.wait(); } } finish_concurrent_resizing(); }