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 Service thread (serviceThread.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 ServiceThread; |
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 |
294 | |