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
64class OopClosure;
65class MemoryPool;
66
67class 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
116class SensorInfo : public CHeapObj<mtInternal> {
117private:
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);
140public:
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
214class LowMemoryDetector : public AllStatic {
215 friend class LowMemoryDetectorDisabler;
216 friend class ServiceThread;
217private:
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
230public:
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
280class LowMemoryDetectorDisabler: public StackObj {
281public:
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