aoqi@0: /* aoqi@0: * Copyright (c) 2003, 2012, 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: #ifndef SHARE_VM_SERVICES_LOWMEMORYDETECTOR_HPP aoqi@0: #define SHARE_VM_SERVICES_LOWMEMORYDETECTOR_HPP aoqi@0: aoqi@0: #include "memory/allocation.hpp" aoqi@0: #include "services/memoryPool.hpp" aoqi@0: #include "services/memoryService.hpp" aoqi@0: aoqi@0: // Low Memory Detection Support aoqi@0: // Two memory alarms in the JDK (we called them sensors). aoqi@0: // - Heap memory sensor aoqi@0: // - Non-heap memory sensor aoqi@0: // When the VM detects if the memory usage of a memory pool has reached aoqi@0: // or exceeded its threshold, it will trigger the sensor for the type aoqi@0: // of the memory pool (heap or nonheap or both). aoqi@0: // aoqi@0: // If threshold == -1, no low memory detection is supported and aoqi@0: // the threshold value is not allowed to be changed. aoqi@0: // If threshold == 0, no low memory detection is performed for aoqi@0: // that memory pool. The threshold can be set to any non-negative aoqi@0: // value. aoqi@0: // aoqi@0: // The default threshold of the Hotspot memory pools are: aoqi@0: // Eden space -1 aoqi@0: // Survivor space 1 -1 aoqi@0: // Survivor space 2 -1 aoqi@0: // Old generation 0 aoqi@0: // Perm generation 0 aoqi@0: // CodeCache 0 aoqi@0: // aoqi@0: // For heap memory, detection will be performed when GC finishes aoqi@0: // and also in the slow path allocation. aoqi@0: // For Code cache, detection will be performed in the allocation aoqi@0: // and deallocation. aoqi@0: // aoqi@0: // May need to deal with hysteresis effect. aoqi@0: // aoqi@0: // Memory detection code runs in the Service thread (serviceThread.hpp). aoqi@0: aoqi@0: class OopClosure; aoqi@0: class MemoryPool; aoqi@0: aoqi@0: class ThresholdSupport : public CHeapObj { aoqi@0: private: aoqi@0: bool _support_high_threshold; aoqi@0: bool _support_low_threshold; aoqi@0: size_t _high_threshold; aoqi@0: size_t _low_threshold; aoqi@0: public: aoqi@0: ThresholdSupport(bool support_high, bool support_low) { aoqi@0: _support_high_threshold = support_high; aoqi@0: _support_low_threshold = support_low; aoqi@0: _high_threshold = 0; aoqi@0: _low_threshold= 0; aoqi@0: } aoqi@0: aoqi@0: size_t high_threshold() const { return _high_threshold; } aoqi@0: size_t low_threshold() const { return _low_threshold; } aoqi@0: bool is_high_threshold_supported() { return _support_high_threshold; } aoqi@0: bool is_low_threshold_supported() { return _support_low_threshold; } aoqi@0: aoqi@0: bool is_high_threshold_crossed(MemoryUsage usage) { aoqi@0: if (_support_high_threshold && _high_threshold > 0) { aoqi@0: return (usage.used() >= _high_threshold); aoqi@0: } aoqi@0: return false; aoqi@0: } aoqi@0: bool is_low_threshold_crossed(MemoryUsage usage) { aoqi@0: if (_support_low_threshold && _low_threshold > 0) { aoqi@0: return (usage.used() < _low_threshold); aoqi@0: } aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: size_t set_high_threshold(size_t new_threshold) { aoqi@0: assert(_support_high_threshold, "can only be set if supported"); aoqi@0: assert(new_threshold >= _low_threshold, "new_threshold must be >= _low_threshold"); aoqi@0: size_t prev = _high_threshold; aoqi@0: _high_threshold = new_threshold; aoqi@0: return prev; aoqi@0: } aoqi@0: aoqi@0: size_t set_low_threshold(size_t new_threshold) { aoqi@0: assert(_support_low_threshold, "can only be set if supported"); aoqi@0: assert(new_threshold <= _high_threshold, "new_threshold must be <= _high_threshold"); aoqi@0: size_t prev = _low_threshold; aoqi@0: _low_threshold = new_threshold; aoqi@0: return prev; aoqi@0: } aoqi@0: }; aoqi@0: aoqi@0: class SensorInfo : public CHeapObj { aoqi@0: private: aoqi@0: instanceOop _sensor_obj; aoqi@0: bool _sensor_on; aoqi@0: size_t _sensor_count; aoqi@0: aoqi@0: // before the actual sensor on flag and sensor count are set aoqi@0: // we maintain the number of pending triggers and clears. aoqi@0: // _pending_trigger_count means the number of pending triggers aoqi@0: // and the sensor count should be incremented by the same number. aoqi@0: aoqi@0: int _pending_trigger_count; aoqi@0: aoqi@0: // _pending_clear_count takes precedence if it's > 0 which aoqi@0: // indicates the resulting sensor will be off aoqi@0: // Sensor trigger requests will reset this clear count to aoqi@0: // indicate the resulting flag should be on. aoqi@0: aoqi@0: int _pending_clear_count; aoqi@0: aoqi@0: MemoryUsage _usage; aoqi@0: aoqi@0: void clear(int count, TRAPS); aoqi@0: void trigger(int count, TRAPS); aoqi@0: public: aoqi@0: SensorInfo(); aoqi@0: void set_sensor(instanceOop sensor) { aoqi@0: assert(_sensor_obj == NULL, "Should be set only once"); aoqi@0: _sensor_obj = sensor; aoqi@0: } aoqi@0: aoqi@0: bool has_pending_requests() { aoqi@0: return (_pending_trigger_count > 0 || _pending_clear_count > 0); aoqi@0: } aoqi@0: aoqi@0: int pending_trigger_count() { return _pending_trigger_count; } aoqi@0: int pending_clear_count() { return _pending_clear_count; } aoqi@0: aoqi@0: // When this method is used, the memory usage is monitored aoqi@0: // as a gauge attribute. High and low thresholds are designed aoqi@0: // to provide a 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 set_gauge_sensor_level(MemoryUsage usage, ThresholdSupport* high_low_threshold); 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: // 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: // aoqi@0: void set_counter_sensor_level(MemoryUsage usage, ThresholdSupport* counter_threshold); aoqi@0: aoqi@0: void process_pending_requests(TRAPS); aoqi@0: void oops_do(OopClosure* f); aoqi@0: aoqi@0: #ifndef PRODUCT aoqi@0: // printing on default output stream; aoqi@0: void print(); aoqi@0: #endif // PRODUCT aoqi@0: }; aoqi@0: aoqi@0: class LowMemoryDetector : public AllStatic { aoqi@0: friend class LowMemoryDetectorDisabler; aoqi@0: friend class ServiceThread; aoqi@0: private: aoqi@0: // true if any collected heap has low memory detection enabled aoqi@0: static volatile bool _enabled_for_collected_pools; aoqi@0: // > 0 if temporary disabed aoqi@0: static volatile jint _disabled_count; aoqi@0: aoqi@0: static void check_memory_usage(); aoqi@0: static bool has_pending_requests(); aoqi@0: static bool temporary_disabled() { return _disabled_count > 0; } aoqi@0: static void disable() { Atomic::inc(&_disabled_count); } aoqi@0: static void enable() { Atomic::dec(&_disabled_count); } aoqi@0: static void process_sensor_changes(TRAPS); aoqi@0: aoqi@0: public: aoqi@0: static void detect_low_memory(); aoqi@0: static void detect_low_memory(MemoryPool* pool); aoqi@0: static void detect_after_gc_memory(MemoryPool* pool); aoqi@0: aoqi@0: static bool is_enabled(MemoryPool* pool) { aoqi@0: // low memory detection is enabled for collected memory pools aoqi@0: // iff one of the collected memory pool has a sensor and the aoqi@0: // threshold set non-zero aoqi@0: if (pool->usage_sensor() == NULL) { aoqi@0: return false; aoqi@0: } else { aoqi@0: ThresholdSupport* threshold_support = pool->usage_threshold(); aoqi@0: return (threshold_support->is_high_threshold_supported() ? aoqi@0: (threshold_support->high_threshold() > 0) : false); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // indicates if low memory detection is enabled for any collected aoqi@0: // memory pools aoqi@0: static inline bool is_enabled_for_collected_pools() { aoqi@0: return !temporary_disabled() && _enabled_for_collected_pools; aoqi@0: } aoqi@0: aoqi@0: // recompute enabled flag aoqi@0: static void recompute_enabled_for_collected_pools(); aoqi@0: aoqi@0: // low memory detection for collected memory pools. aoqi@0: static inline void detect_low_memory_for_collected_pools() { aoqi@0: // no-op if low memory detection not enabled aoqi@0: if (!is_enabled_for_collected_pools()) { aoqi@0: return; aoqi@0: } aoqi@0: int num_memory_pools = MemoryService::num_memory_pools(); aoqi@0: for (int i=0; iis_collected_pool() && is_enabled(pool)) { aoqi@0: size_t used = pool->used_in_bytes(); aoqi@0: size_t high = pool->usage_threshold()->high_threshold(); aoqi@0: if (used > high) { aoqi@0: detect_low_memory(pool); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: }; aoqi@0: aoqi@0: class LowMemoryDetectorDisabler: public StackObj { aoqi@0: public: aoqi@0: LowMemoryDetectorDisabler() aoqi@0: { aoqi@0: LowMemoryDetector::disable(); aoqi@0: } aoqi@0: ~LowMemoryDetectorDisabler() aoqi@0: { aoqi@0: assert(LowMemoryDetector::temporary_disabled(), "should be disabled!"); aoqi@0: LowMemoryDetector::enable(); aoqi@0: } aoqi@0: }; aoqi@0: aoqi@0: #endif // SHARE_VM_SERVICES_LOWMEMORYDETECTOR_HPP