lowMemoryDetector.hpp revision 1472:c18cbe5936b8
1/* 2 * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25// Low Memory Detection Support 26// Two memory alarms in the JDK (we called them sensors). 27// - Heap memory sensor 28// - Non-heap memory sensor 29// When the VM detects if the memory usage of a memory pool has reached 30// or exceeded its threshold, it will trigger the sensor for the type 31// of the memory pool (heap or nonheap or both). 32// 33// If threshold == -1, no low memory detection is supported and 34// the threshold value is not allowed to be changed. 35// If threshold == 0, no low memory detection is performed for 36// that memory pool. The threshold can be set to any non-negative 37// value. 38// 39// The default threshold of the Hotspot memory pools are: 40// Eden space -1 41// Survivor space 1 -1 42// Survivor space 2 -1 43// Old generation 0 44// Perm generation 0 45// CodeCache 0 46// 47// For heap memory, detection will be performed when GC finishes 48// and also in the slow path allocation. 49// For Code cache, detection will be performed in the allocation 50// and deallocation. 51// 52// May need to deal with hysteresis effect. 53// 54 55class LowMemoryDetectorThread; 56class OopClosure; 57class MemoryPool; 58 59class ThresholdSupport : public CHeapObj { 60 private: 61 bool _support_high_threshold; 62 bool _support_low_threshold; 63 size_t _high_threshold; 64 size_t _low_threshold; 65 public: 66 ThresholdSupport(bool support_high, bool support_low) { 67 _support_high_threshold = support_high; 68 _support_low_threshold = support_low; 69 _high_threshold = 0; 70 _low_threshold= 0; 71 } 72 73 size_t high_threshold() const { return _high_threshold; } 74 size_t low_threshold() const { return _low_threshold; } 75 bool is_high_threshold_supported() { return _support_high_threshold; } 76 bool is_low_threshold_supported() { return _support_low_threshold; } 77 78 bool is_high_threshold_crossed(MemoryUsage usage) { 79 if (_support_high_threshold && _high_threshold > 0) { 80 return (usage.used() >= _high_threshold); 81 } 82 return false; 83 } 84 bool is_low_threshold_crossed(MemoryUsage usage) { 85 if (_support_low_threshold && _low_threshold > 0) { 86 return (usage.used() < _low_threshold); 87 } 88 return false; 89 } 90 91 size_t set_high_threshold(size_t new_threshold) { 92 assert(_support_high_threshold, "can only be set if supported"); 93 assert(new_threshold >= _low_threshold, "new_threshold must be >= _low_threshold"); 94 size_t prev = _high_threshold; 95 _high_threshold = new_threshold; 96 return prev; 97 } 98 99 size_t set_low_threshold(size_t new_threshold) { 100 assert(_support_low_threshold, "can only be set if supported"); 101 assert(new_threshold <= _high_threshold, "new_threshold must be <= _high_threshold"); 102 size_t prev = _low_threshold; 103 _low_threshold = new_threshold; 104 return prev; 105 } 106}; 107 108class SensorInfo : public CHeapObj { 109private: 110 instanceOop _sensor_obj; 111 bool _sensor_on; 112 size_t _sensor_count; 113 114 // before the actual sensor on flag and sensor count are set 115 // we maintain the number of pending triggers and clears. 116 // _pending_trigger_count means the number of pending triggers 117 // and the sensor count should be incremented by the same number. 118 119 int _pending_trigger_count; 120 121 // _pending_clear_count takes precedence if it's > 0 which 122 // indicates the resulting sensor will be off 123 // Sensor trigger requests will reset this clear count to 124 // indicate the resulting flag should be on. 125 126 int _pending_clear_count; 127 128 MemoryUsage _usage; 129 130 void clear(int count, TRAPS); 131 void trigger(int count, TRAPS); 132public: 133 SensorInfo(); 134 void set_sensor(instanceOop sensor) { 135 assert(_sensor_obj == NULL, "Should be set only once"); 136 _sensor_obj = sensor; 137 } 138 139 bool has_pending_requests() { 140 return (_pending_trigger_count > 0 || _pending_clear_count > 0); 141 } 142 143 int pending_trigger_count() { return _pending_trigger_count; } 144 int pending_clear_count() { return _pending_clear_count; } 145 146 // When this method is used, the memory usage is monitored 147 // as a gauge attribute. High and low thresholds are designed 148 // to provide a hysteresis mechanism to avoid repeated triggering 149 // of notifications when the attribute value makes small oscillations 150 // around the high or low threshold value. 151 // 152 // The sensor will be triggered if: 153 // (1) the usage is crossing above the high threshold and 154 // the sensor is currently off and no pending 155 // trigger requests; or 156 // (2) the usage is crossing above the high threshold and 157 // the sensor will be off (i.e. sensor is currently on 158 // and has pending clear requests). 159 // 160 // Subsequent crossings of the high threshold value do not cause 161 // any triggers unless the usage becomes less than the low threshold. 162 // 163 // The sensor will be cleared if: 164 // (1) the usage is crossing below the low threshold and 165 // the sensor is currently on and no pending 166 // clear requests; or 167 // (2) the usage is crossing below the low threshold and 168 // the sensor will be on (i.e. sensor is currently off 169 // and has pending trigger requests). 170 // 171 // Subsequent crossings of the low threshold value do not cause 172 // any clears unless the usage becomes greater than or equal 173 // to the high threshold. 174 // 175 // If the current level is between high and low threhsold, no change. 176 // 177 void set_gauge_sensor_level(MemoryUsage usage, ThresholdSupport* high_low_threshold); 178 179 // When this method is used, the memory usage is monitored as a 180 // simple counter attribute. The sensor will be triggered 181 // whenever the usage is crossing the threshold to keep track 182 // of the number of times the VM detects such a condition occurs. 183 // 184 // The sensor will be triggered if: 185 // - the usage is crossing above the high threshold regardless 186 // of the current sensor state. 187 // 188 // The sensor will be cleared if: 189 // (1) the usage is crossing below the low threshold and 190 // the sensor is currently on; or 191 // (2) the usage is crossing below the low threshold and 192 // the sensor will be on (i.e. sensor is currently off 193 // and has pending trigger requests). 194 // 195 void set_counter_sensor_level(MemoryUsage usage, ThresholdSupport* counter_threshold); 196 197 void process_pending_requests(TRAPS); 198 void oops_do(OopClosure* f); 199 200#ifndef PRODUCT 201 // printing on default output stream; 202 void print(); 203#endif // PRODUCT 204}; 205 206class LowMemoryDetector : public AllStatic { 207friend class LowMemoryDetectorDisabler; 208private: 209 // true if any collected heap has low memory detection enabled 210 static volatile bool _enabled_for_collected_pools; 211 // > 0 if temporary disabed 212 static volatile jint _disabled_count; 213 214 static LowMemoryDetectorThread* _detector_thread; 215 static void low_memory_detector_thread_entry(JavaThread* thread, TRAPS); 216 static void check_memory_usage(); 217 static bool has_pending_requests(); 218 static bool temporary_disabled() { return _disabled_count > 0; } 219 static void disable() { Atomic::inc(&_disabled_count); } 220 static void enable() { Atomic::dec(&_disabled_count); } 221 222public: 223 static void initialize(); 224 static void detect_low_memory(); 225 static void detect_low_memory(MemoryPool* pool); 226 static void detect_after_gc_memory(MemoryPool* pool); 227 228 static bool is_enabled(MemoryPool* pool) { 229 // low memory detection is enabled for collected memory pools 230 // iff one of the collected memory pool has a sensor and the 231 // threshold set non-zero 232 if (pool->usage_sensor() == NULL) { 233 return false; 234 } else { 235 ThresholdSupport* threshold_support = pool->usage_threshold(); 236 return (threshold_support->is_high_threshold_supported() ? 237 (threshold_support->high_threshold() > 0) : false); 238 } 239 } 240 241 // indicates if low memory detection is enabled for any collected 242 // memory pools 243 static inline bool is_enabled_for_collected_pools() { 244 return !temporary_disabled() && _enabled_for_collected_pools; 245 } 246 247 // recompute enabled flag 248 static void recompute_enabled_for_collected_pools(); 249 250 // low memory detection for collected memory pools. 251 static inline void detect_low_memory_for_collected_pools() { 252 // no-op if low memory detection not enabled 253 if (!is_enabled_for_collected_pools()) { 254 return; 255 } 256 int num_memory_pools = MemoryService::num_memory_pools(); 257 for (int i=0; i<num_memory_pools; i++) { 258 MemoryPool* pool = MemoryService::get_memory_pool(i); 259 260 // if low memory detection is enabled then check if the 261 // current used exceeds the high threshold 262 if (pool->is_collected_pool() && is_enabled(pool)) { 263 size_t used = pool->used_in_bytes(); 264 size_t high = pool->usage_threshold()->high_threshold(); 265 if (used > high) { 266 detect_low_memory(pool); 267 } 268 } 269 } 270 } 271 272}; 273 274class LowMemoryDetectorDisabler: public StackObj { 275public: 276 LowMemoryDetectorDisabler() 277 { 278 LowMemoryDetector::disable(); 279 } 280 ~LowMemoryDetectorDisabler() 281 { 282 assert(LowMemoryDetector::temporary_disabled(), "should be disabled!"); 283 LowMemoryDetector::enable(); 284 } 285}; 286