1 /* 2 * Copyright (c) 2003, 2019, 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 #ifndef SHARE_SERVICES_LOWMEMORYDETECTOR_HPP 26 #define SHARE_SERVICES_LOWMEMORYDETECTOR_HPP 27 28 #include "memory/allocation.hpp" 29 #include "services/memoryPool.hpp" 30 #include "services/memoryService.hpp" 31 #include "services/memoryUsage.hpp" 32 33 // Low Memory Detection Support 34 // Two memory alarms in the JDK (we called them sensors). 35 // - Heap memory sensor 36 // - Non-heap memory sensor 37 // When the VM detects if the memory usage of a memory pool has reached 38 // or exceeded its threshold, it will trigger the sensor for the type 39 // of the memory pool (heap or nonheap or both). 40 // 41 // If threshold == -1, no low memory detection is supported and 42 // the threshold value is not allowed to be changed. 43 // If threshold == 0, no low memory detection is performed for 44 // that memory pool. The threshold can be set to any non-negative 45 // value. 46 // 47 // The default threshold of the Hotspot memory pools are: 48 // Eden space -1 49 // Survivor space 1 -1 50 // Survivor space 2 -1 51 // Old generation 0 52 // Perm generation 0 53 // CodeCache 0 54 // 55 // For heap memory, detection will be performed when GC finishes 56 // and also in the slow path allocation. 57 // For Code cache, detection will be performed in the allocation 58 // and deallocation. 59 // 60 // May need to deal with hysteresis effect. 61 // 62 // Memory detection code runs in the Notification thread (notificationThread.hpp). 63 64 class OopClosure; 65 class MemoryPool; 66 67 class ThresholdSupport : public CHeapObj<mtInternal> { 68 private: 69 bool _support_high_threshold; 70 bool _support_low_threshold; 71 size_t _high_threshold; 72 size_t _low_threshold; 73 public: 74 ThresholdSupport(bool support_high, bool support_low) { 75 _support_high_threshold = support_high; 76 _support_low_threshold = support_low; 77 _high_threshold = 0; 78 _low_threshold= 0; 79 } 80 81 size_t high_threshold() const { return _high_threshold; } 82 size_t low_threshold() const { return _low_threshold; } 83 bool is_high_threshold_supported() { return _support_high_threshold; } 84 bool is_low_threshold_supported() { return _support_low_threshold; } 85 86 bool is_high_threshold_crossed(MemoryUsage usage) { 87 if (_support_high_threshold && _high_threshold > 0) { 88 return (usage.used() >= _high_threshold); 89 } 90 return false; 91 } 92 bool is_low_threshold_crossed(MemoryUsage usage) { 93 if (_support_low_threshold && _low_threshold > 0) { 94 return (usage.used() < _low_threshold); 95 } 96 return false; 97 } 98 99 size_t set_high_threshold(size_t new_threshold) { 100 assert(_support_high_threshold, "can only be set if supported"); 101 assert(new_threshold >= _low_threshold, "new_threshold must be >= _low_threshold"); 102 size_t prev = _high_threshold; 103 _high_threshold = new_threshold; 104 return prev; 105 } 106 107 size_t set_low_threshold(size_t new_threshold) { 108 assert(_support_low_threshold, "can only be set if supported"); 109 assert(new_threshold <= _high_threshold, "new_threshold must be <= _high_threshold"); 110 size_t prev = _low_threshold; 111 _low_threshold = new_threshold; 112 return prev; 113 } 114 }; 115 116 class SensorInfo : public CHeapObj<mtInternal> { 117 private: 118 instanceOop _sensor_obj; 119 bool _sensor_on; 120 size_t _sensor_count; 121 122 // before the actual sensor on flag and sensor count are set 123 // we maintain the number of pending triggers and clears. 124 // _pending_trigger_count means the number of pending triggers 125 // and the sensor count should be incremented by the same number. 126 127 int _pending_trigger_count; 128 129 // _pending_clear_count takes precedence if it's > 0 which 130 // indicates the resulting sensor will be off 131 // Sensor trigger requests will reset this clear count to 132 // indicate the resulting flag should be on. 133 134 int _pending_clear_count; 135 136 MemoryUsage _usage; 137 138 void clear(int count, TRAPS); 139 void trigger(int count, TRAPS); 140 public: 141 SensorInfo(); 142 void set_sensor(instanceOop sensor) { 143 assert(_sensor_obj == NULL, "Should be set only once"); 144 _sensor_obj = sensor; 145 } 146 147 bool has_pending_requests() { 148 return (_pending_trigger_count > 0 || _pending_clear_count > 0); 149 } 150 151 int pending_trigger_count() { return _pending_trigger_count; } 152 int pending_clear_count() { return _pending_clear_count; } 153 154 // When this method is used, the memory usage is monitored 155 // as a gauge attribute. High and low thresholds are designed 156 // to provide a hysteresis mechanism to avoid repeated triggering 157 // of notifications when the attribute value makes small oscillations 158 // around the high or low threshold value. 159 // 160 // The sensor will be triggered if: 161 // (1) the usage is crossing above the high threshold and 162 // the sensor is currently off and no pending 163 // trigger requests; or 164 // (2) the usage is crossing above the high threshold and 165 // the sensor will be off (i.e. sensor is currently on 166 // and has pending clear requests). 167 // 168 // Subsequent crossings of the high threshold value do not cause 169 // any triggers unless the usage becomes less than the low threshold. 170 // 171 // The sensor will be cleared if: 172 // (1) the usage is crossing below the low threshold and 173 // the sensor is currently on and no pending 174 // clear requests; or 175 // (2) the usage is crossing below the low threshold and 176 // the sensor will be on (i.e. sensor is currently off 177 // and has pending trigger requests). 178 // 179 // Subsequent crossings of the low threshold value do not cause 180 // any clears unless the usage becomes greater than or equal 181 // to the high threshold. 182 // 183 // If the current level is between high and low threshold, no change. 184 // 185 void set_gauge_sensor_level(MemoryUsage usage, ThresholdSupport* high_low_threshold); 186 187 // When this method is used, the memory usage is monitored as a 188 // simple counter attribute. The sensor will be triggered 189 // whenever the usage is crossing the threshold to keep track 190 // of the number of times the VM detects such a condition occurs. 191 // 192 // The sensor will be triggered if: 193 // - the usage is crossing above the high threshold regardless 194 // of the current sensor state. 195 // 196 // The sensor will be cleared if: 197 // (1) the usage is crossing below the low threshold and 198 // the sensor is currently on; or 199 // (2) the usage is crossing below the low threshold and 200 // the sensor will be on (i.e. sensor is currently off 201 // and has pending trigger requests). 202 // 203 void set_counter_sensor_level(MemoryUsage usage, ThresholdSupport* counter_threshold); 204 205 void process_pending_requests(TRAPS); 206 void oops_do(OopClosure* f); 207 208 #ifndef PRODUCT 209 // printing on default output stream; 210 void print(); 211 #endif // PRODUCT 212 }; 213 214 class LowMemoryDetector : public AllStatic { 215 friend class LowMemoryDetectorDisabler; 216 friend class NotificationThread; 217 private: 218 // true if any collected heap has low memory detection enabled 219 static volatile bool _enabled_for_collected_pools; 220 // > 0 if temporary disabed 221 static volatile jint _disabled_count; 222 223 static void check_memory_usage(); 224 static bool has_pending_requests(); 225 static bool temporary_disabled() { return _disabled_count > 0; } 226 static void disable() { Atomic::inc(&_disabled_count); } 227 static void enable() { Atomic::dec(&_disabled_count); } 228 static void process_sensor_changes(TRAPS); 229 230 public: 231 static void detect_low_memory(); 232 static void detect_low_memory(MemoryPool* pool); 233 static void detect_after_gc_memory(MemoryPool* pool); 234 235 static bool is_enabled(MemoryPool* pool) { 236 // low memory detection is enabled for collected memory pools 237 // iff one of the collected memory pool has a sensor and the 238 // threshold set non-zero 239 if (pool->usage_sensor() == NULL) { 240 return false; 241 } else { 242 ThresholdSupport* threshold_support = pool->usage_threshold(); 243 return (threshold_support->is_high_threshold_supported() ? 244 (threshold_support->high_threshold() > 0) : false); 245 } 246 } 247 248 // indicates if low memory detection is enabled for any collected 249 // memory pools 250 static inline bool is_enabled_for_collected_pools() { 251 return !temporary_disabled() && _enabled_for_collected_pools; 252 } 253 254 // recompute enabled flag 255 static void recompute_enabled_for_collected_pools(); 256 257 // low memory detection for collected memory pools. 258 static inline void detect_low_memory_for_collected_pools() { 259 // no-op if low memory detection not enabled 260 if (!is_enabled_for_collected_pools()) { 261 return; 262 } 263 int num_memory_pools = MemoryService::num_memory_pools(); 264 for (int i=0; i<num_memory_pools; i++) { 265 MemoryPool* pool = MemoryService::get_memory_pool(i); 266 267 // if low memory detection is enabled then check if the 268 // current used exceeds the high threshold 269 if (pool->is_collected_pool() && is_enabled(pool)) { 270 size_t used = pool->used_in_bytes(); 271 size_t high = pool->usage_threshold()->high_threshold(); 272 if (used > high) { 273 detect_low_memory(pool); 274 } 275 } 276 } 277 } 278 }; 279 280 class LowMemoryDetectorDisabler: public StackObj { 281 public: 282 LowMemoryDetectorDisabler() 283 { 284 LowMemoryDetector::disable(); 285 } 286 ~LowMemoryDetectorDisabler() 287 { 288 assert(LowMemoryDetector::temporary_disabled(), "should be disabled!"); 289 LowMemoryDetector::enable(); 290 } 291 }; 292 293 #endif // SHARE_SERVICES_LOWMEMORYDETECTOR_HPP