aoqi@0: /* aoqi@0: * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: * aoqi@0: */ aoqi@0: aoqi@0: #include "precompiled.hpp" aoqi@0: #include "classfile/systemDictionary.hpp" aoqi@0: #include "classfile/vmSymbols.hpp" aoqi@0: #include "oops/oop.inline.hpp" aoqi@0: #include "runtime/interfaceSupport.hpp" aoqi@0: #include "runtime/java.hpp" aoqi@0: #include "runtime/javaCalls.hpp" aoqi@0: #include "runtime/mutex.hpp" aoqi@0: #include "runtime/mutexLocker.hpp" aoqi@0: #include "services/lowMemoryDetector.hpp" aoqi@0: #include "services/management.hpp" aoqi@0: aoqi@0: volatile bool LowMemoryDetector::_enabled_for_collected_pools = false; aoqi@0: volatile jint LowMemoryDetector::_disabled_count = 0; aoqi@0: aoqi@0: bool LowMemoryDetector::has_pending_requests() { aoqi@0: assert(Service_lock->owned_by_self(), "Must own Service_lock"); aoqi@0: bool has_requests = false; aoqi@0: int num_memory_pools = MemoryService::num_memory_pools(); aoqi@0: for (int i = 0; i < num_memory_pools; i++) { aoqi@0: MemoryPool* pool = MemoryService::get_memory_pool(i); aoqi@0: SensorInfo* sensor = pool->usage_sensor(); aoqi@0: if (sensor != NULL) { aoqi@0: has_requests = has_requests || sensor->has_pending_requests(); aoqi@0: } aoqi@0: aoqi@0: SensorInfo* gc_sensor = pool->gc_usage_sensor(); aoqi@0: if (gc_sensor != NULL) { aoqi@0: has_requests = has_requests || gc_sensor->has_pending_requests(); aoqi@0: } aoqi@0: } aoqi@0: return has_requests; aoqi@0: } aoqi@0: aoqi@0: void LowMemoryDetector::process_sensor_changes(TRAPS) { aoqi@0: ResourceMark rm(THREAD); aoqi@0: HandleMark hm(THREAD); aoqi@0: aoqi@0: // No need to hold Service_lock to call out to Java aoqi@0: int num_memory_pools = MemoryService::num_memory_pools(); aoqi@0: for (int i = 0; i < num_memory_pools; i++) { aoqi@0: MemoryPool* pool = MemoryService::get_memory_pool(i); aoqi@0: SensorInfo* sensor = pool->usage_sensor(); aoqi@0: SensorInfo* gc_sensor = pool->gc_usage_sensor(); aoqi@0: if (sensor != NULL && sensor->has_pending_requests()) { aoqi@0: sensor->process_pending_requests(CHECK); aoqi@0: } aoqi@0: if (gc_sensor != NULL && gc_sensor->has_pending_requests()) { aoqi@0: gc_sensor->process_pending_requests(CHECK); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // This method could be called from any Java threads aoqi@0: // and also VMThread. aoqi@0: void LowMemoryDetector::detect_low_memory() { aoqi@0: MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag); aoqi@0: aoqi@0: bool has_pending_requests = false; aoqi@0: int num_memory_pools = MemoryService::num_memory_pools(); aoqi@0: for (int i = 0; i < num_memory_pools; i++) { aoqi@0: MemoryPool* pool = MemoryService::get_memory_pool(i); aoqi@0: SensorInfo* sensor = pool->usage_sensor(); aoqi@0: if (sensor != NULL && aoqi@0: pool->usage_threshold()->is_high_threshold_supported() && aoqi@0: pool->usage_threshold()->high_threshold() != 0) { aoqi@0: MemoryUsage usage = pool->get_memory_usage(); aoqi@0: sensor->set_gauge_sensor_level(usage, aoqi@0: pool->usage_threshold()); aoqi@0: has_pending_requests = has_pending_requests || sensor->has_pending_requests(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: if (has_pending_requests) { aoqi@0: Service_lock->notify_all(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // This method could be called from any Java threads aoqi@0: // and also VMThread. aoqi@0: void LowMemoryDetector::detect_low_memory(MemoryPool* pool) { aoqi@0: SensorInfo* sensor = pool->usage_sensor(); aoqi@0: if (sensor == NULL || aoqi@0: !pool->usage_threshold()->is_high_threshold_supported() || aoqi@0: pool->usage_threshold()->high_threshold() == 0) { aoqi@0: return; aoqi@0: } aoqi@0: aoqi@0: { aoqi@0: MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag); aoqi@0: aoqi@0: MemoryUsage usage = pool->get_memory_usage(); aoqi@0: sensor->set_gauge_sensor_level(usage, aoqi@0: pool->usage_threshold()); aoqi@0: if (sensor->has_pending_requests()) { aoqi@0: // notify sensor state update aoqi@0: Service_lock->notify_all(); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // Only called by VMThread at GC time aoqi@0: void LowMemoryDetector::detect_after_gc_memory(MemoryPool* pool) { aoqi@0: SensorInfo* sensor = pool->gc_usage_sensor(); aoqi@0: if (sensor == NULL || aoqi@0: !pool->gc_usage_threshold()->is_high_threshold_supported() || aoqi@0: pool->gc_usage_threshold()->high_threshold() == 0) { aoqi@0: return; aoqi@0: } aoqi@0: aoqi@0: { aoqi@0: MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag); aoqi@0: aoqi@0: MemoryUsage usage = pool->get_last_collection_usage(); aoqi@0: sensor->set_counter_sensor_level(usage, pool->gc_usage_threshold()); aoqi@0: aoqi@0: if (sensor->has_pending_requests()) { aoqi@0: // notify sensor state update aoqi@0: Service_lock->notify_all(); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // recompute enabled flag aoqi@0: void LowMemoryDetector::recompute_enabled_for_collected_pools() { aoqi@0: bool enabled = false; aoqi@0: int num_memory_pools = MemoryService::num_memory_pools(); aoqi@0: for (int i=0; iis_collected_pool() && is_enabled(pool)) { aoqi@0: enabled = true; aoqi@0: break; aoqi@0: } aoqi@0: } aoqi@0: _enabled_for_collected_pools = enabled; aoqi@0: } aoqi@0: aoqi@0: SensorInfo::SensorInfo() { aoqi@0: _sensor_obj = NULL; aoqi@0: _sensor_on = false; aoqi@0: _sensor_count = 0; aoqi@0: _pending_trigger_count = 0; aoqi@0: _pending_clear_count = 0; aoqi@0: } aoqi@0: aoqi@0: // When this method is used, the memory usage is monitored aoqi@0: // as a gauge attribute. Sensor notifications (trigger or aoqi@0: // clear) is only emitted at the first time it crosses aoqi@0: // a threshold. aoqi@0: // aoqi@0: // High and low thresholds are designed to provide a aoqi@0: // hysteresis mechanism to avoid repeated triggering aoqi@0: // of notifications when the attribute value makes small oscillations aoqi@0: // around the high or low threshold value. aoqi@0: // aoqi@0: // The sensor will be triggered if: aoqi@0: // (1) the usage is crossing above the high threshold and aoqi@0: // the sensor is currently off and no pending aoqi@0: // trigger requests; or aoqi@0: // (2) the usage is crossing above the high threshold and aoqi@0: // the sensor will be off (i.e. sensor is currently on aoqi@0: // and has pending clear requests). aoqi@0: // aoqi@0: // Subsequent crossings of the high threshold value do not cause aoqi@0: // any triggers unless the usage becomes less than the low threshold. aoqi@0: // aoqi@0: // The sensor will be cleared if: aoqi@0: // (1) the usage is crossing below the low threshold and aoqi@0: // the sensor is currently on and no pending aoqi@0: // clear requests; or aoqi@0: // (2) the usage is crossing below the low threshold and aoqi@0: // the sensor will be on (i.e. sensor is currently off aoqi@0: // and has pending trigger requests). aoqi@0: // aoqi@0: // Subsequent crossings of the low threshold value do not cause aoqi@0: // any clears unless the usage becomes greater than or equal aoqi@0: // to the high threshold. aoqi@0: // aoqi@0: // If the current level is between high and low threhsold, no change. aoqi@0: // aoqi@0: void SensorInfo::set_gauge_sensor_level(MemoryUsage usage, ThresholdSupport* high_low_threshold) { aoqi@0: assert(high_low_threshold->is_high_threshold_supported(), "just checking"); aoqi@0: aoqi@0: bool is_over_high = high_low_threshold->is_high_threshold_crossed(usage); aoqi@0: bool is_below_low = high_low_threshold->is_low_threshold_crossed(usage); aoqi@0: aoqi@0: assert(!(is_over_high && is_below_low), "Can't be both true"); aoqi@0: aoqi@0: if (is_over_high && aoqi@0: ((!_sensor_on && _pending_trigger_count == 0) || aoqi@0: _pending_clear_count > 0)) { aoqi@0: // low memory detected and need to increment the trigger pending count aoqi@0: // if the sensor is off or will be off due to _pending_clear_ > 0 aoqi@0: // Request to trigger the sensor aoqi@0: _pending_trigger_count++; aoqi@0: _usage = usage; aoqi@0: aoqi@0: if (_pending_clear_count > 0) { aoqi@0: // non-zero pending clear requests indicates that there are aoqi@0: // pending requests to clear this sensor. aoqi@0: // This trigger request needs to clear this clear count aoqi@0: // since the resulting sensor flag should be on. aoqi@0: _pending_clear_count = 0; aoqi@0: } aoqi@0: } else if (is_below_low && aoqi@0: ((_sensor_on && _pending_clear_count == 0) || aoqi@0: (_pending_trigger_count > 0 && _pending_clear_count == 0))) { aoqi@0: // memory usage returns below the threshold aoqi@0: // Request to clear the sensor if the sensor is on or will be on due to aoqi@0: // _pending_trigger_count > 0 and also no clear request aoqi@0: _pending_clear_count++; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // When this method is used, the memory usage is monitored as a aoqi@0: // simple counter attribute. The sensor will be triggered aoqi@0: // whenever the usage is crossing the threshold to keep track aoqi@0: // of the number of times the VM detects such a condition occurs. aoqi@0: // aoqi@0: // High and low thresholds are designed to provide a aoqi@0: // hysteresis mechanism to avoid repeated triggering aoqi@0: // of notifications when the attribute value makes small oscillations aoqi@0: // around the high or low threshold value. aoqi@0: // aoqi@0: // The sensor will be triggered if: aoqi@0: // - the usage is crossing above the high threshold regardless aoqi@0: // of the current sensor state. aoqi@0: // aoqi@0: // The sensor will be cleared if: aoqi@0: // (1) the usage is crossing below the low threshold and aoqi@0: // the sensor is currently on; or aoqi@0: // (2) the usage is crossing below the low threshold and aoqi@0: // the sensor will be on (i.e. sensor is currently off aoqi@0: // and has pending trigger requests). aoqi@0: void SensorInfo::set_counter_sensor_level(MemoryUsage usage, ThresholdSupport* counter_threshold) { aoqi@0: assert(counter_threshold->is_high_threshold_supported(), "just checking"); aoqi@0: aoqi@0: bool is_over_high = counter_threshold->is_high_threshold_crossed(usage); aoqi@0: bool is_below_low = counter_threshold->is_low_threshold_crossed(usage); aoqi@0: aoqi@0: assert(!(is_over_high && is_below_low), "Can't be both true"); aoqi@0: aoqi@0: if (is_over_high) { aoqi@0: _pending_trigger_count++; aoqi@0: _usage = usage; aoqi@0: _pending_clear_count = 0; aoqi@0: } else if (is_below_low && (_sensor_on || _pending_trigger_count > 0)) { aoqi@0: _pending_clear_count++; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: void SensorInfo::oops_do(OopClosure* f) { aoqi@0: f->do_oop((oop*) &_sensor_obj); aoqi@0: } aoqi@0: aoqi@0: void SensorInfo::process_pending_requests(TRAPS) { aoqi@0: if (!has_pending_requests()) { aoqi@0: return; aoqi@0: } aoqi@0: aoqi@0: int pending_count = pending_trigger_count(); aoqi@0: if (pending_clear_count() > 0) { aoqi@0: clear(pending_count, CHECK); aoqi@0: } else { aoqi@0: trigger(pending_count, CHECK); aoqi@0: } aoqi@0: aoqi@0: } aoqi@0: aoqi@0: void SensorInfo::trigger(int count, TRAPS) { aoqi@0: assert(count <= _pending_trigger_count, "just checking"); aoqi@0: aoqi@0: if (_sensor_obj != NULL) { aoqi@0: Klass* k = Management::sun_management_Sensor_klass(CHECK); aoqi@0: instanceKlassHandle sensorKlass (THREAD, k); aoqi@0: Handle sensor_h(THREAD, _sensor_obj); aoqi@0: Handle usage_h = MemoryService::create_MemoryUsage_obj(_usage, CHECK); aoqi@0: aoqi@0: JavaValue result(T_VOID); aoqi@0: JavaCallArguments args(sensor_h); aoqi@0: args.push_int((int) count); aoqi@0: args.push_oop(usage_h); aoqi@0: aoqi@0: JavaCalls::call_virtual(&result, aoqi@0: sensorKlass, aoqi@0: vmSymbols::trigger_name(), aoqi@0: vmSymbols::trigger_method_signature(), aoqi@0: &args, aoqi@0: CHECK); aoqi@0: } aoqi@0: aoqi@0: { aoqi@0: // Holds Service_lock and update the sensor state aoqi@0: MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag); aoqi@0: _sensor_on = true; aoqi@0: _sensor_count += count; aoqi@0: _pending_trigger_count = _pending_trigger_count - count; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: void SensorInfo::clear(int count, TRAPS) { aoqi@0: if (_sensor_obj != NULL) { aoqi@0: Klass* k = Management::sun_management_Sensor_klass(CHECK); aoqi@0: instanceKlassHandle sensorKlass (THREAD, k); aoqi@0: Handle sensor(THREAD, _sensor_obj); aoqi@0: aoqi@0: JavaValue result(T_VOID); aoqi@0: JavaCallArguments args(sensor); aoqi@0: args.push_int((int) count); aoqi@0: JavaCalls::call_virtual(&result, aoqi@0: sensorKlass, aoqi@0: vmSymbols::clear_name(), aoqi@0: vmSymbols::int_void_signature(), aoqi@0: &args, aoqi@0: CHECK); aoqi@0: } aoqi@0: aoqi@0: { aoqi@0: // Holds Service_lock and update the sensor state aoqi@0: MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag); aoqi@0: _sensor_on = false; aoqi@0: _pending_clear_count = 0; aoqi@0: _pending_trigger_count = _pending_trigger_count - count; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: //-------------------------------------------------------------- aoqi@0: // Non-product code aoqi@0: aoqi@0: #ifndef PRODUCT aoqi@0: void SensorInfo::print() { aoqi@0: tty->print_cr("%s count = " SIZE_FORMAT " pending_triggers = %d pending_clears = %d", aoqi@0: (_sensor_on ? "on" : "off"), aoqi@0: _sensor_count, _pending_trigger_count, _pending_clear_count); aoqi@0: } aoqi@0: aoqi@0: #endif // PRODUCT