duke@435: /* duke@435: * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. duke@435: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: * duke@435: * This code is free software; you can redistribute it and/or modify it duke@435: * under the terms of the GNU General Public License version 2 only, as duke@435: * published by the Free Software Foundation. duke@435: * duke@435: * This code is distributed in the hope that it will be useful, but WITHOUT duke@435: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: * version 2 for more details (a copy is included in the LICENSE file that duke@435: * accompanied this code). duke@435: * duke@435: * You should have received a copy of the GNU General Public License version duke@435: * 2 along with this work; if not, write to the Free Software Foundation, duke@435: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: * duke@435: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, duke@435: * CA 95054 USA or visit www.sun.com if you need additional information or duke@435: * have any questions. duke@435: * duke@435: */ duke@435: duke@435: # include "incls/_precompiled.incl" duke@435: # include "incls/_lowMemoryDetector.cpp.incl" duke@435: duke@435: LowMemoryDetectorThread* LowMemoryDetector::_detector_thread = NULL; duke@435: volatile bool LowMemoryDetector::_enabled_for_collected_pools = false; duke@435: volatile jint LowMemoryDetector::_disabled_count = 0; duke@435: duke@435: void LowMemoryDetector::initialize() { duke@435: EXCEPTION_MARK; duke@435: duke@435: instanceKlassHandle klass (THREAD, SystemDictionary::thread_klass()); duke@435: instanceHandle thread_oop = klass->allocate_instance_handle(CHECK); duke@435: duke@435: const char thread_name[] = "Low Memory Detector"; duke@435: Handle string = java_lang_String::create_from_str(thread_name, CHECK); duke@435: duke@435: // Initialize thread_oop to put it into the system threadGroup duke@435: Handle thread_group (THREAD, Universe::system_thread_group()); duke@435: JavaValue result(T_VOID); duke@435: JavaCalls::call_special(&result, thread_oop, duke@435: klass, duke@435: vmSymbolHandles::object_initializer_name(), duke@435: vmSymbolHandles::threadgroup_string_void_signature(), duke@435: thread_group, duke@435: string, duke@435: CHECK); duke@435: duke@435: { duke@435: MutexLocker mu(Threads_lock); duke@435: _detector_thread = new LowMemoryDetectorThread(&low_memory_detector_thread_entry); duke@435: duke@435: // At this point it may be possible that no osthread was created for the duke@435: // JavaThread due to lack of memory. We would have to throw an exception duke@435: // in that case. However, since this must work and we do not allow duke@435: // exceptions anyway, check and abort if this fails. duke@435: if (_detector_thread == NULL || _detector_thread->osthread() == NULL) { duke@435: vm_exit_during_initialization("java.lang.OutOfMemoryError", duke@435: "unable to create new native thread"); duke@435: } duke@435: duke@435: java_lang_Thread::set_thread(thread_oop(), _detector_thread); duke@435: java_lang_Thread::set_priority(thread_oop(), NearMaxPriority); duke@435: java_lang_Thread::set_daemon(thread_oop()); duke@435: _detector_thread->set_threadObj(thread_oop()); duke@435: duke@435: Threads::add(_detector_thread); duke@435: Thread::start(_detector_thread); duke@435: } duke@435: } duke@435: duke@435: bool LowMemoryDetector::has_pending_requests() { duke@435: assert(LowMemory_lock->owned_by_self(), "Must own LowMemory_lock"); duke@435: bool has_requests = false; duke@435: int num_memory_pools = MemoryService::num_memory_pools(); duke@435: for (int i = 0; i < num_memory_pools; i++) { duke@435: MemoryPool* pool = MemoryService::get_memory_pool(i); duke@435: SensorInfo* sensor = pool->usage_sensor(); duke@435: if (sensor != NULL) { duke@435: has_requests = has_requests || sensor->has_pending_requests(); duke@435: } duke@435: duke@435: SensorInfo* gc_sensor = pool->gc_usage_sensor(); duke@435: if (gc_sensor != NULL) { duke@435: has_requests = has_requests || gc_sensor->has_pending_requests(); duke@435: } duke@435: } duke@435: return has_requests; duke@435: } duke@435: duke@435: void LowMemoryDetector::low_memory_detector_thread_entry(JavaThread* jt, TRAPS) { duke@435: while (true) { duke@435: bool sensors_changed = false; duke@435: duke@435: { duke@435: // _no_safepoint_check_flag is used here as LowMemory_lock is a duke@435: // special lock and the VMThread may acquire this lock at safepoint. duke@435: // Need state transition ThreadBlockInVM so that this thread duke@435: // will be handled by safepoint correctly when this thread is duke@435: // notified at a safepoint. duke@435: duke@435: // This ThreadBlockInVM object is not also considered to be duke@435: // suspend-equivalent because LowMemoryDetector threads are duke@435: // not visible to external suspension. duke@435: duke@435: ThreadBlockInVM tbivm(jt); duke@435: duke@435: MutexLockerEx ml(LowMemory_lock, Mutex::_no_safepoint_check_flag); duke@435: while (!(sensors_changed = has_pending_requests())) { duke@435: // wait until one of the sensors has pending requests duke@435: LowMemory_lock->wait(Mutex::_no_safepoint_check_flag); duke@435: } duke@435: } duke@435: duke@435: { duke@435: ResourceMark rm(THREAD); duke@435: HandleMark hm(THREAD); duke@435: duke@435: // No need to hold LowMemory_lock to call out to Java duke@435: int num_memory_pools = MemoryService::num_memory_pools(); duke@435: for (int i = 0; i < num_memory_pools; i++) { duke@435: MemoryPool* pool = MemoryService::get_memory_pool(i); duke@435: SensorInfo* sensor = pool->usage_sensor(); duke@435: SensorInfo* gc_sensor = pool->gc_usage_sensor(); duke@435: if (sensor != NULL && sensor->has_pending_requests()) { duke@435: sensor->process_pending_requests(CHECK); duke@435: } duke@435: if (gc_sensor != NULL && gc_sensor->has_pending_requests()) { duke@435: gc_sensor->process_pending_requests(CHECK); duke@435: } duke@435: } duke@435: } duke@435: } duke@435: } duke@435: duke@435: // This method could be called from any Java threads duke@435: // and also VMThread. duke@435: void LowMemoryDetector::detect_low_memory() { duke@435: MutexLockerEx ml(LowMemory_lock, Mutex::_no_safepoint_check_flag); duke@435: duke@435: bool has_pending_requests = false; duke@435: int num_memory_pools = MemoryService::num_memory_pools(); duke@435: for (int i = 0; i < num_memory_pools; i++) { duke@435: MemoryPool* pool = MemoryService::get_memory_pool(i); duke@435: SensorInfo* sensor = pool->usage_sensor(); duke@435: if (sensor != NULL && duke@435: pool->usage_threshold()->is_high_threshold_supported() && duke@435: pool->usage_threshold()->high_threshold() != 0) { duke@435: MemoryUsage usage = pool->get_memory_usage(); duke@435: sensor->set_gauge_sensor_level(usage, duke@435: pool->usage_threshold()); duke@435: has_pending_requests = has_pending_requests || sensor->has_pending_requests(); duke@435: } duke@435: } duke@435: duke@435: if (has_pending_requests) { duke@435: LowMemory_lock->notify_all(); duke@435: } duke@435: } duke@435: duke@435: // This method could be called from any Java threads duke@435: // and also VMThread. duke@435: void LowMemoryDetector::detect_low_memory(MemoryPool* pool) { duke@435: SensorInfo* sensor = pool->usage_sensor(); duke@435: if (sensor == NULL || duke@435: !pool->usage_threshold()->is_high_threshold_supported() || duke@435: pool->usage_threshold()->high_threshold() == 0) { duke@435: return; duke@435: } duke@435: duke@435: { duke@435: MutexLockerEx ml(LowMemory_lock, Mutex::_no_safepoint_check_flag); duke@435: duke@435: MemoryUsage usage = pool->get_memory_usage(); duke@435: sensor->set_gauge_sensor_level(usage, duke@435: pool->usage_threshold()); duke@435: if (sensor->has_pending_requests()) { duke@435: // notify sensor state update duke@435: LowMemory_lock->notify_all(); duke@435: } duke@435: } duke@435: } duke@435: duke@435: // Only called by VMThread at GC time duke@435: void LowMemoryDetector::detect_after_gc_memory(MemoryPool* pool) { duke@435: SensorInfo* sensor = pool->gc_usage_sensor(); duke@435: if (sensor == NULL || duke@435: !pool->gc_usage_threshold()->is_high_threshold_supported() || duke@435: pool->gc_usage_threshold()->high_threshold() == 0) { duke@435: return; duke@435: } duke@435: duke@435: { duke@435: MutexLockerEx ml(LowMemory_lock, Mutex::_no_safepoint_check_flag); duke@435: duke@435: MemoryUsage usage = pool->get_last_collection_usage(); duke@435: sensor->set_counter_sensor_level(usage, pool->gc_usage_threshold()); duke@435: duke@435: if (sensor->has_pending_requests()) { duke@435: // notify sensor state update duke@435: LowMemory_lock->notify_all(); duke@435: } duke@435: } duke@435: } duke@435: duke@435: // recompute enabled flag duke@435: void LowMemoryDetector::recompute_enabled_for_collected_pools() { duke@435: bool enabled = false; duke@435: int num_memory_pools = MemoryService::num_memory_pools(); duke@435: for (int i=0; iis_collected_pool() && is_enabled(pool)) { duke@435: enabled = true; duke@435: break; duke@435: } duke@435: } duke@435: _enabled_for_collected_pools = enabled; duke@435: } duke@435: duke@435: SensorInfo::SensorInfo() { duke@435: _sensor_obj = NULL; duke@435: _sensor_on = false; duke@435: _sensor_count = 0; duke@435: _pending_trigger_count = 0; duke@435: _pending_clear_count = 0; duke@435: } duke@435: duke@435: // When this method is used, the memory usage is monitored duke@435: // as a gauge attribute. Sensor notifications (trigger or duke@435: // clear) is only emitted at the first time it crosses duke@435: // a threshold. duke@435: // duke@435: // High and low thresholds are designed to provide a duke@435: // hysteresis mechanism to avoid repeated triggering duke@435: // of notifications when the attribute value makes small oscillations duke@435: // around the high or low threshold value. duke@435: // duke@435: // The sensor will be triggered if: duke@435: // (1) the usage is crossing above the high threshold and duke@435: // the sensor is currently off and no pending duke@435: // trigger requests; or duke@435: // (2) the usage is crossing above the high threshold and duke@435: // the sensor will be off (i.e. sensor is currently on duke@435: // and has pending clear requests). duke@435: // duke@435: // Subsequent crossings of the high threshold value do not cause duke@435: // any triggers unless the usage becomes less than the low threshold. duke@435: // duke@435: // The sensor will be cleared if: duke@435: // (1) the usage is crossing below the low threshold and duke@435: // the sensor is currently on and no pending duke@435: // clear requests; or duke@435: // (2) the usage is crossing below the low threshold and duke@435: // the sensor will be on (i.e. sensor is currently off duke@435: // and has pending trigger requests). duke@435: // duke@435: // Subsequent crossings of the low threshold value do not cause duke@435: // any clears unless the usage becomes greater than or equal duke@435: // to the high threshold. duke@435: // duke@435: // If the current level is between high and low threhsold, no change. duke@435: // duke@435: void SensorInfo::set_gauge_sensor_level(MemoryUsage usage, ThresholdSupport* high_low_threshold) { duke@435: assert(high_low_threshold->is_high_threshold_supported(), "just checking"); duke@435: duke@435: bool is_over_high = high_low_threshold->is_high_threshold_crossed(usage); duke@435: bool is_below_low = high_low_threshold->is_low_threshold_crossed(usage); duke@435: duke@435: assert(!(is_over_high && is_below_low), "Can't be both true"); duke@435: duke@435: if (is_over_high && duke@435: ((!_sensor_on && _pending_trigger_count == 0) || duke@435: _pending_clear_count > 0)) { duke@435: // low memory detected and need to increment the trigger pending count duke@435: // if the sensor is off or will be off due to _pending_clear_ > 0 duke@435: // Request to trigger the sensor duke@435: _pending_trigger_count++; duke@435: _usage = usage; duke@435: duke@435: if (_pending_clear_count > 0) { duke@435: // non-zero pending clear requests indicates that there are duke@435: // pending requests to clear this sensor. duke@435: // This trigger request needs to clear this clear count duke@435: // since the resulting sensor flag should be on. duke@435: _pending_clear_count = 0; duke@435: } duke@435: } else if (is_below_low && duke@435: ((_sensor_on && _pending_clear_count == 0) || duke@435: (_pending_trigger_count > 0 && _pending_clear_count == 0))) { duke@435: // memory usage returns below the threshold duke@435: // Request to clear the sensor if the sensor is on or will be on due to duke@435: // _pending_trigger_count > 0 and also no clear request duke@435: _pending_clear_count++; duke@435: } duke@435: } duke@435: duke@435: // When this method is used, the memory usage is monitored as a duke@435: // simple counter attribute. The sensor will be triggered duke@435: // whenever the usage is crossing the threshold to keep track duke@435: // of the number of times the VM detects such a condition occurs. duke@435: // duke@435: // High and low thresholds are designed to provide a duke@435: // hysteresis mechanism to avoid repeated triggering duke@435: // of notifications when the attribute value makes small oscillations duke@435: // around the high or low threshold value. duke@435: // duke@435: // The sensor will be triggered if: duke@435: // - the usage is crossing above the high threshold regardless duke@435: // of the current sensor state. duke@435: // duke@435: // The sensor will be cleared if: duke@435: // (1) the usage is crossing below the low threshold and duke@435: // the sensor is currently on; or duke@435: // (2) the usage is crossing below the low threshold and duke@435: // the sensor will be on (i.e. sensor is currently off duke@435: // and has pending trigger requests). duke@435: void SensorInfo::set_counter_sensor_level(MemoryUsage usage, ThresholdSupport* counter_threshold) { duke@435: assert(counter_threshold->is_high_threshold_supported(), "just checking"); duke@435: duke@435: bool is_over_high = counter_threshold->is_high_threshold_crossed(usage); duke@435: bool is_below_low = counter_threshold->is_low_threshold_crossed(usage); duke@435: duke@435: assert(!(is_over_high && is_below_low), "Can't be both true"); duke@435: duke@435: if (is_over_high) { duke@435: _pending_trigger_count++; duke@435: _usage = usage; duke@435: _pending_clear_count = 0; duke@435: } else if (is_below_low && (_sensor_on || _pending_trigger_count > 0)) { duke@435: _pending_clear_count++; duke@435: } duke@435: } duke@435: duke@435: void SensorInfo::oops_do(OopClosure* f) { duke@435: f->do_oop((oop*) &_sensor_obj); duke@435: } duke@435: duke@435: void SensorInfo::process_pending_requests(TRAPS) { duke@435: if (!has_pending_requests()) { duke@435: return; duke@435: } duke@435: duke@435: int pending_count = pending_trigger_count(); duke@435: if (pending_clear_count() > 0) { duke@435: clear(pending_count, CHECK); duke@435: } else { duke@435: trigger(pending_count, CHECK); duke@435: } duke@435: duke@435: } duke@435: duke@435: void SensorInfo::trigger(int count, TRAPS) { duke@435: assert(count <= _pending_trigger_count, "just checking"); duke@435: duke@435: if (_sensor_obj != NULL) { duke@435: klassOop k = Management::sun_management_Sensor_klass(CHECK); duke@435: instanceKlassHandle sensorKlass (THREAD, k); duke@435: Handle sensor_h(THREAD, _sensor_obj); duke@435: Handle usage_h = MemoryService::create_MemoryUsage_obj(_usage, CHECK); duke@435: duke@435: JavaValue result(T_VOID); duke@435: JavaCallArguments args(sensor_h); duke@435: args.push_int((int) count); duke@435: args.push_oop(usage_h); duke@435: duke@435: JavaCalls::call_virtual(&result, duke@435: sensorKlass, duke@435: vmSymbolHandles::trigger_name(), duke@435: vmSymbolHandles::trigger_method_signature(), duke@435: &args, duke@435: CHECK); duke@435: } duke@435: duke@435: { duke@435: // Holds LowMemory_lock and update the sensor state duke@435: MutexLockerEx ml(LowMemory_lock, Mutex::_no_safepoint_check_flag); duke@435: _sensor_on = true; duke@435: _sensor_count += count; duke@435: _pending_trigger_count = _pending_trigger_count - count; duke@435: } duke@435: } duke@435: duke@435: void SensorInfo::clear(int count, TRAPS) { duke@435: if (_sensor_obj != NULL) { duke@435: klassOop k = Management::sun_management_Sensor_klass(CHECK); duke@435: instanceKlassHandle sensorKlass (THREAD, k); duke@435: Handle sensor(THREAD, _sensor_obj); duke@435: duke@435: JavaValue result(T_VOID); duke@435: JavaCallArguments args(sensor); duke@435: args.push_int((int) count); duke@435: JavaCalls::call_virtual(&result, duke@435: sensorKlass, duke@435: vmSymbolHandles::clear_name(), duke@435: vmSymbolHandles::int_void_signature(), duke@435: &args, duke@435: CHECK); duke@435: } duke@435: duke@435: { duke@435: // Holds LowMemory_lock and update the sensor state duke@435: MutexLockerEx ml(LowMemory_lock, Mutex::_no_safepoint_check_flag); duke@435: _sensor_on = false; duke@435: _pending_clear_count = 0; duke@435: _pending_trigger_count = _pending_trigger_count - count; duke@435: } duke@435: } duke@435: duke@435: //-------------------------------------------------------------- duke@435: // Non-product code duke@435: duke@435: #ifndef PRODUCT duke@435: void SensorInfo::print() { duke@435: tty->print_cr("%s count = %ld pending_triggers = %ld pending_clears = %ld", duke@435: (_sensor_on ? "on" : "off"), duke@435: _sensor_count, _pending_trigger_count, _pending_clear_count); duke@435: } duke@435: duke@435: #endif // PRODUCT