src/share/vm/services/lowMemoryDetector.hpp

changeset 435
a61af66fc99e
child 1907
c18cbe5936b8
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/share/vm/services/lowMemoryDetector.hpp	Sat Dec 01 00:00:00 2007 +0000
     1.3 @@ -0,0 +1,285 @@
     1.4 +/*
     1.5 + * Copyright 2003-2007 Sun Microsystems, Inc.  All Rights Reserved.
     1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.7 + *
     1.8 + * This code is free software; you can redistribute it and/or modify it
     1.9 + * under the terms of the GNU General Public License version 2 only, as
    1.10 + * published by the Free Software Foundation.
    1.11 + *
    1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.15 + * version 2 for more details (a copy is included in the LICENSE file that
    1.16 + * accompanied this code).
    1.17 + *
    1.18 + * You should have received a copy of the GNU General Public License version
    1.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.21 + *
    1.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
    1.23 + * CA 95054 USA or visit www.sun.com if you need additional information or
    1.24 + * have any questions.
    1.25 + *
    1.26 + */
    1.27 +
    1.28 +// Low Memory Detection Support
    1.29 +// Two memory alarms in the JDK (we called them sensors).
    1.30 +//   - Heap memory sensor
    1.31 +//   - Non-heap memory sensor
    1.32 +// When the VM detects if the memory usage of a memory pool has reached
    1.33 +// or exceeded its threshold, it will trigger the sensor for the type
    1.34 +// of the memory pool (heap or nonheap or both).
    1.35 +//
    1.36 +// If threshold == -1, no low memory detection is supported and
    1.37 +// the threshold value is not allowed to be changed.
    1.38 +// If threshold == 0, no low memory detection is performed for
    1.39 +// that memory pool.  The threshold can be set to any non-negative
    1.40 +// value.
    1.41 +//
    1.42 +// The default threshold of the Hotspot memory pools are:
    1.43 +//   Eden space        -1
    1.44 +//   Survivor space 1  -1
    1.45 +//   Survivor space 2  -1
    1.46 +//   Old generation    0
    1.47 +//   Perm generation   0
    1.48 +//   CodeCache         0
    1.49 +//
    1.50 +// For heap memory, detection will be performed when GC finishes
    1.51 +// and also in the slow path allocation.
    1.52 +// For Code cache, detection will be performed in the allocation
    1.53 +// and deallocation.
    1.54 +//
    1.55 +// May need to deal with hysteresis effect.
    1.56 +//
    1.57 +
    1.58 +class LowMemoryDetectorThread;
    1.59 +class OopClosure;
    1.60 +class MemoryPool;
    1.61 +
    1.62 +class ThresholdSupport : public CHeapObj {
    1.63 + private:
    1.64 +  bool            _support_high_threshold;
    1.65 +  bool            _support_low_threshold;
    1.66 +  size_t          _high_threshold;
    1.67 +  size_t          _low_threshold;
    1.68 + public:
    1.69 +  ThresholdSupport(bool support_high, bool support_low) {
    1.70 +    _support_high_threshold = support_high;
    1.71 +    _support_low_threshold = support_low;
    1.72 +    _high_threshold = 0;
    1.73 +    _low_threshold= 0;
    1.74 +  }
    1.75 +
    1.76 +  size_t      high_threshold() const        { return _high_threshold; }
    1.77 +  size_t      low_threshold()  const        { return _low_threshold; }
    1.78 +  bool        is_high_threshold_supported() { return _support_high_threshold; }
    1.79 +  bool        is_low_threshold_supported()  { return _support_low_threshold; }
    1.80 +
    1.81 +  bool        is_high_threshold_crossed(MemoryUsage usage) {
    1.82 +    if (_support_high_threshold && _high_threshold > 0) {
    1.83 +      return (usage.used() >= _high_threshold);
    1.84 +    }
    1.85 +    return false;
    1.86 +  }
    1.87 +  bool        is_low_threshold_crossed(MemoryUsage usage) {
    1.88 +    if (_support_low_threshold && _low_threshold > 0) {
    1.89 +      return (usage.used() < _low_threshold);
    1.90 +    }
    1.91 +    return false;
    1.92 +  }
    1.93 +
    1.94 +  size_t      set_high_threshold(size_t new_threshold) {
    1.95 +    assert(_support_high_threshold, "can only be set if supported");
    1.96 +    assert(new_threshold >= _low_threshold, "new_threshold must be >= _low_threshold");
    1.97 +    size_t prev = _high_threshold;
    1.98 +    _high_threshold = new_threshold;
    1.99 +    return prev;
   1.100 +  }
   1.101 +
   1.102 +  size_t      set_low_threshold(size_t new_threshold) {
   1.103 +    assert(_support_low_threshold, "can only be set if supported");
   1.104 +    assert(new_threshold <= _high_threshold, "new_threshold must be <= _high_threshold");
   1.105 +    size_t prev = _low_threshold;
   1.106 +    _low_threshold = new_threshold;
   1.107 +    return prev;
   1.108 +  }
   1.109 +};
   1.110 +
   1.111 +class SensorInfo : public CHeapObj {
   1.112 +private:
   1.113 +  instanceOop     _sensor_obj;
   1.114 +  bool            _sensor_on;
   1.115 +  size_t          _sensor_count;
   1.116 +
   1.117 +  // before the actual sensor on flag and sensor count are set
   1.118 +  // we maintain the number of pending triggers and clears.
   1.119 +  // _pending_trigger_count means the number of pending triggers
   1.120 +  // and the sensor count should be incremented by the same number.
   1.121 +
   1.122 +  int             _pending_trigger_count;
   1.123 +
   1.124 +  // _pending_clear_count takes precedence if it's > 0 which
   1.125 +  // indicates the resulting sensor will be off
   1.126 +  // Sensor trigger requests will reset this clear count to
   1.127 +  // indicate the resulting flag should be on.
   1.128 +
   1.129 +  int             _pending_clear_count;
   1.130 +
   1.131 +  MemoryUsage     _usage;
   1.132 +
   1.133 +  void clear(int count, TRAPS);
   1.134 +  void trigger(int count, TRAPS);
   1.135 +public:
   1.136 +  SensorInfo();
   1.137 +  void set_sensor(instanceOop sensor) {
   1.138 +    assert(_sensor_obj == NULL, "Should be set only once");
   1.139 +    _sensor_obj = sensor;
   1.140 +  }
   1.141 +
   1.142 +  bool has_pending_requests() {
   1.143 +    return (_pending_trigger_count > 0 || _pending_clear_count > 0);
   1.144 +  }
   1.145 +
   1.146 +  int pending_trigger_count()      { return _pending_trigger_count; }
   1.147 +  int pending_clear_count()        { return _pending_clear_count; }
   1.148 +
   1.149 +  // When this method is used, the memory usage is monitored
   1.150 +  // as a gauge attribute.  High and low thresholds are designed
   1.151 +  // to provide a hysteresis mechanism to avoid repeated triggering
   1.152 +  // of notifications when the attribute value makes small oscillations
   1.153 +  // around the high or low threshold value.
   1.154 +  //
   1.155 +  // The sensor will be triggered if:
   1.156 +  //  (1) the usage is crossing above the high threshold and
   1.157 +  //      the sensor is currently off and no pending
   1.158 +  //      trigger requests; or
   1.159 +  //  (2) the usage is crossing above the high threshold and
   1.160 +  //      the sensor will be off (i.e. sensor is currently on
   1.161 +  //      and has pending clear requests).
   1.162 +  //
   1.163 +  // Subsequent crossings of the high threshold value do not cause
   1.164 +  // any triggers unless the usage becomes less than the low threshold.
   1.165 +  //
   1.166 +  // The sensor will be cleared if:
   1.167 +  //  (1) the usage is crossing below the low threshold and
   1.168 +  //      the sensor is currently on and no pending
   1.169 +  //      clear requests; or
   1.170 +  //  (2) the usage is crossing below the low threshold and
   1.171 +  //      the sensor will be on (i.e. sensor is currently off
   1.172 +  //      and has pending trigger requests).
   1.173 +  //
   1.174 +  // Subsequent crossings of the low threshold value do not cause
   1.175 +  // any clears unless the usage becomes greater than or equal
   1.176 +  // to the high threshold.
   1.177 +  //
   1.178 +  // If the current level is between high and low threhsold, no change.
   1.179 +  //
   1.180 +  void set_gauge_sensor_level(MemoryUsage usage, ThresholdSupport* high_low_threshold);
   1.181 +
   1.182 +  // When this method is used, the memory usage is monitored as a
   1.183 +  // simple counter attribute.  The sensor will be triggered
   1.184 +  // whenever the usage is crossing the threshold to keep track
   1.185 +  // of the number of times the VM detects such a condition occurs.
   1.186 +  //
   1.187 +  // The sensor will be triggered if:
   1.188 +  //   - the usage is crossing above the high threshold regardless
   1.189 +  //     of the current sensor state.
   1.190 +  //
   1.191 +  // The sensor will be cleared if:
   1.192 +  //  (1) the usage is crossing below the low threshold and
   1.193 +  //      the sensor is currently on; or
   1.194 +  //  (2) the usage is crossing below the low threshold and
   1.195 +  //      the sensor will be on (i.e. sensor is currently off
   1.196 +  //      and has pending trigger requests).
   1.197 +  //
   1.198 +  void set_counter_sensor_level(MemoryUsage usage, ThresholdSupport* counter_threshold);
   1.199 +
   1.200 +  void process_pending_requests(TRAPS);
   1.201 +  void oops_do(OopClosure* f);
   1.202 +
   1.203 +#ifndef PRODUCT
   1.204 +  // printing on default output stream;
   1.205 +  void print();
   1.206 +#endif // PRODUCT
   1.207 +};
   1.208 +
   1.209 +class LowMemoryDetector : public AllStatic {
   1.210 +friend class LowMemoryDetectorDisabler;
   1.211 +private:
   1.212 +  // true if any collected heap has low memory detection enabled
   1.213 +  static volatile bool _enabled_for_collected_pools;
   1.214 +  // > 0 if temporary disabed
   1.215 +  static volatile jint _disabled_count;
   1.216 +
   1.217 +  static LowMemoryDetectorThread* _detector_thread;
   1.218 +  static void low_memory_detector_thread_entry(JavaThread* thread, TRAPS);
   1.219 +  static void check_memory_usage();
   1.220 +  static bool has_pending_requests();
   1.221 +  static bool temporary_disabled() { return _disabled_count > 0; }
   1.222 +  static void disable() { Atomic::inc(&_disabled_count); }
   1.223 +  static void enable() { Atomic::dec(&_disabled_count); }
   1.224 +
   1.225 +public:
   1.226 +  static void initialize();
   1.227 +  static void detect_low_memory();
   1.228 +  static void detect_low_memory(MemoryPool* pool);
   1.229 +  static void detect_after_gc_memory(MemoryPool* pool);
   1.230 +
   1.231 +  static bool is_enabled(MemoryPool* pool) {
   1.232 +    // low memory detection is enabled for collected memory pools
   1.233 +    // iff one of the collected memory pool has a sensor and the
   1.234 +    // threshold set non-zero
   1.235 +    if (pool->usage_sensor() == NULL) {
   1.236 +      return false;
   1.237 +    } else {
   1.238 +      ThresholdSupport* threshold_support = pool->usage_threshold();
   1.239 +      return (threshold_support->is_high_threshold_supported() ?
   1.240 +               (threshold_support->high_threshold() > 0) : false);
   1.241 +    }
   1.242 +  }
   1.243 +
   1.244 +  // indicates if low memory detection is enabled for any collected
   1.245 +  // memory pools
   1.246 +  static inline bool is_enabled_for_collected_pools() {
   1.247 +    return !temporary_disabled() && _enabled_for_collected_pools;
   1.248 +  }
   1.249 +
   1.250 +  // recompute enabled flag
   1.251 +  static void recompute_enabled_for_collected_pools();
   1.252 +
   1.253 +  // low memory detection for collected memory pools.
   1.254 +  static inline void detect_low_memory_for_collected_pools() {
   1.255 +    // no-op if low memory detection not enabled
   1.256 +    if (!is_enabled_for_collected_pools()) {
   1.257 +      return;
   1.258 +    }
   1.259 +    int num_memory_pools = MemoryService::num_memory_pools();
   1.260 +    for (int i=0; i<num_memory_pools; i++) {
   1.261 +      MemoryPool* pool = MemoryService::get_memory_pool(i);
   1.262 +
   1.263 +      // if low memory detection is enabled then check if the
   1.264 +      // current used exceeds the high threshold
   1.265 +      if (pool->is_collected_pool() && is_enabled(pool)) {
   1.266 +        size_t used = pool->used_in_bytes();
   1.267 +        size_t high = pool->usage_threshold()->high_threshold();
   1.268 +        if (used > high) {
   1.269 +          detect_low_memory(pool);
   1.270 +        }
   1.271 +      }
   1.272 +    }
   1.273 +  }
   1.274 +
   1.275 +};
   1.276 +
   1.277 +class LowMemoryDetectorDisabler: public StackObj {
   1.278 +public:
   1.279 +  LowMemoryDetectorDisabler()
   1.280 +  {
   1.281 +    LowMemoryDetector::disable();
   1.282 +  }
   1.283 +  ~LowMemoryDetectorDisabler()
   1.284 +  {
   1.285 +    assert(LowMemoryDetector::temporary_disabled(), "should be disabled!");
   1.286 +    LowMemoryDetector::enable();
   1.287 +  }
   1.288 +};

mercurial