Path: blob/master/src/hotspot/share/services/lowMemoryDetector.hpp
41144 views
/*1* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#ifndef SHARE_SERVICES_LOWMEMORYDETECTOR_HPP25#define SHARE_SERVICES_LOWMEMORYDETECTOR_HPP2627#include "memory/allocation.hpp"28#include "oops/oopHandle.hpp"29#include "runtime/atomic.hpp"30#include "services/memoryPool.hpp"31#include "services/memoryService.hpp"32#include "services/memoryUsage.hpp"3334// Low Memory Detection Support35// Two memory alarms in the JDK (we called them sensors).36// - Heap memory sensor37// - Non-heap memory sensor38// When the VM detects if the memory usage of a memory pool has reached39// or exceeded its threshold, it will trigger the sensor for the type40// of the memory pool (heap or nonheap or both).41//42// If threshold == -1, no low memory detection is supported and43// the threshold value is not allowed to be changed.44// If threshold == 0, no low memory detection is performed for45// that memory pool. The threshold can be set to any non-negative46// value.47//48// The default threshold of the Hotspot memory pools are:49// Eden space -150// Survivor space 1 -151// Survivor space 2 -152// Old generation 053// Perm generation 054// CodeCache 055//56// For heap memory, detection will be performed when GC finishes57// and also in the slow path allocation.58// For Code cache, detection will be performed in the allocation59// and deallocation.60//61// May need to deal with hysteresis effect.62//63// Memory detection code runs in the Notification thread or64// ServiceThread depending on UseNotificationThread flag.6566class OopClosure;67class MemoryPool;6869class ThresholdSupport : public CHeapObj<mtInternal> {70private:71bool _support_high_threshold;72bool _support_low_threshold;73size_t _high_threshold;74size_t _low_threshold;75public:76ThresholdSupport(bool support_high, bool support_low) {77_support_high_threshold = support_high;78_support_low_threshold = support_low;79_high_threshold = 0;80_low_threshold= 0;81}8283size_t high_threshold() const { return _high_threshold; }84size_t low_threshold() const { return _low_threshold; }85bool is_high_threshold_supported() { return _support_high_threshold; }86bool is_low_threshold_supported() { return _support_low_threshold; }8788bool is_high_threshold_crossed(MemoryUsage usage) {89if (_support_high_threshold && _high_threshold > 0) {90return (usage.used() >= _high_threshold);91}92return false;93}94bool is_low_threshold_crossed(MemoryUsage usage) {95if (_support_low_threshold && _low_threshold > 0) {96return (usage.used() < _low_threshold);97}98return false;99}100101size_t set_high_threshold(size_t new_threshold) {102assert(_support_high_threshold, "can only be set if supported");103assert(new_threshold >= _low_threshold, "new_threshold must be >= _low_threshold");104size_t prev = _high_threshold;105_high_threshold = new_threshold;106return prev;107}108109size_t set_low_threshold(size_t new_threshold) {110assert(_support_low_threshold, "can only be set if supported");111assert(new_threshold <= _high_threshold, "new_threshold must be <= _high_threshold");112size_t prev = _low_threshold;113_low_threshold = new_threshold;114return prev;115}116};117118class SensorInfo : public CHeapObj<mtInternal> {119private:120OopHandle _sensor_obj;121bool _sensor_on;122size_t _sensor_count;123124// before the actual sensor on flag and sensor count are set125// we maintain the number of pending triggers and clears.126// _pending_trigger_count means the number of pending triggers127// and the sensor count should be incremented by the same number.128129int _pending_trigger_count;130131// _pending_clear_count takes precedence if it's > 0 which132// indicates the resulting sensor will be off133// Sensor trigger requests will reset this clear count to134// indicate the resulting flag should be on.135136int _pending_clear_count;137138MemoryUsage _usage;139140void clear(int count, TRAPS);141void trigger(int count, TRAPS);142public:143SensorInfo();144void set_sensor(instanceOop sensor);145146bool has_pending_requests() {147return (_pending_trigger_count > 0 || _pending_clear_count > 0);148}149150int pending_trigger_count() { return _pending_trigger_count; }151int pending_clear_count() { return _pending_clear_count; }152153// When this method is used, the memory usage is monitored154// as a gauge attribute. High and low thresholds are designed155// to provide a hysteresis mechanism to avoid repeated triggering156// of notifications when the attribute value makes small oscillations157// around the high or low threshold value.158//159// The sensor will be triggered if:160// (1) the usage is crossing above the high threshold and161// the sensor is currently off and no pending162// trigger requests; or163// (2) the usage is crossing above the high threshold and164// the sensor will be off (i.e. sensor is currently on165// and has pending clear requests).166//167// Subsequent crossings of the high threshold value do not cause168// any triggers unless the usage becomes less than the low threshold.169//170// The sensor will be cleared if:171// (1) the usage is crossing below the low threshold and172// the sensor is currently on and no pending173// clear requests; or174// (2) the usage is crossing below the low threshold and175// the sensor will be on (i.e. sensor is currently off176// and has pending trigger requests).177//178// Subsequent crossings of the low threshold value do not cause179// any clears unless the usage becomes greater than or equal180// to the high threshold.181//182// If the current level is between high and low threshold, no change.183//184void set_gauge_sensor_level(MemoryUsage usage, ThresholdSupport* high_low_threshold);185186// When this method is used, the memory usage is monitored as a187// simple counter attribute. The sensor will be triggered188// whenever the usage is crossing the threshold to keep track189// of the number of times the VM detects such a condition occurs.190//191// The sensor will be triggered if:192// - the usage is crossing above the high threshold regardless193// of the current sensor state.194//195// The sensor will be cleared if:196// (1) the usage is crossing below the low threshold and197// the sensor is currently on; or198// (2) the usage is crossing below the low threshold and199// the sensor will be on (i.e. sensor is currently off200// and has pending trigger requests).201//202void set_counter_sensor_level(MemoryUsage usage, ThresholdSupport* counter_threshold);203204void process_pending_requests(TRAPS);205206#ifndef PRODUCT207// printing on default output stream;208void print();209#endif // PRODUCT210};211212class LowMemoryDetector : public AllStatic {213friend class ServiceThread;214friend class NotificationThread;215private:216// true if any collected heap has low memory detection enabled217static volatile bool _enabled_for_collected_pools;218219static bool has_pending_requests();220static void process_sensor_changes(TRAPS);221222public:223static void detect_low_memory();224static void detect_low_memory(MemoryPool* pool);225static void detect_after_gc_memory(MemoryPool* pool);226227static bool is_enabled(MemoryPool* pool) {228// low memory detection is enabled for collected memory pools229// iff one of the collected memory pool has a sensor and the230// threshold set non-zero231if (pool->usage_sensor() == NULL) {232return false;233} else {234ThresholdSupport* threshold_support = pool->usage_threshold();235return (threshold_support->is_high_threshold_supported() ?236(threshold_support->high_threshold() > 0) : false);237}238}239240// recompute enabled flag241static void recompute_enabled_for_collected_pools();242243// low memory detection for collected memory pools.244static inline void detect_low_memory_for_collected_pools() {245// no-op if low memory detection not enabled246if (!_enabled_for_collected_pools) {247return;248}249int num_memory_pools = MemoryService::num_memory_pools();250for (int i=0; i<num_memory_pools; i++) {251MemoryPool* pool = MemoryService::get_memory_pool(i);252253// if low memory detection is enabled then check if the254// current used exceeds the high threshold255if (pool->is_collected_pool() && is_enabled(pool)) {256size_t used = pool->used_in_bytes();257size_t high = pool->usage_threshold()->high_threshold();258if (used > high) {259detect_low_memory(pool);260}261}262}263}264};265266#endif // SHARE_SERVICES_LOWMEMORYDETECTOR_HPP267268269