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