--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/services/lowMemoryDetector.hpp Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,285 @@
+/*
+ * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+// Low Memory Detection Support
+// Two memory alarms in the JDK (we called them sensors).
+// - Heap memory sensor
+// - Non-heap memory sensor
+// When the VM detects if the memory usage of a memory pool has reached
+// or exceeded its threshold, it will trigger the sensor for the type
+// of the memory pool (heap or nonheap or both).
+//
+// If threshold == -1, no low memory detection is supported and
+// the threshold value is not allowed to be changed.
+// If threshold == 0, no low memory detection is performed for
+// that memory pool. The threshold can be set to any non-negative
+// value.
+//
+// The default threshold of the Hotspot memory pools are:
+// Eden space -1
+// Survivor space 1 -1
+// Survivor space 2 -1
+// Old generation 0
+// Perm generation 0
+// CodeCache 0
+//
+// For heap memory, detection will be performed when GC finishes
+// and also in the slow path allocation.
+// For Code cache, detection will be performed in the allocation
+// and deallocation.
+//
+// May need to deal with hysteresis effect.
+//
+
+class LowMemoryDetectorThread;
+class OopClosure;
+class MemoryPool;
+
+class ThresholdSupport : public CHeapObj {
+ private:
+ bool _support_high_threshold;
+ bool _support_low_threshold;
+ size_t _high_threshold;
+ size_t _low_threshold;
+ public:
+ ThresholdSupport(bool support_high, bool support_low) {
+ _support_high_threshold = support_high;
+ _support_low_threshold = support_low;
+ _high_threshold = 0;
+ _low_threshold= 0;
+ }
+
+ size_t high_threshold() const { return _high_threshold; }
+ size_t low_threshold() const { return _low_threshold; }
+ bool is_high_threshold_supported() { return _support_high_threshold; }
+ bool is_low_threshold_supported() { return _support_low_threshold; }
+
+ bool is_high_threshold_crossed(MemoryUsage usage) {
+ if (_support_high_threshold && _high_threshold > 0) {
+ return (usage.used() >= _high_threshold);
+ }
+ return false;
+ }
+ bool is_low_threshold_crossed(MemoryUsage usage) {
+ if (_support_low_threshold && _low_threshold > 0) {
+ return (usage.used() < _low_threshold);
+ }
+ return false;
+ }
+
+ size_t set_high_threshold(size_t new_threshold) {
+ assert(_support_high_threshold, "can only be set if supported");
+ assert(new_threshold >= _low_threshold, "new_threshold must be >= _low_threshold");
+ size_t prev = _high_threshold;
+ _high_threshold = new_threshold;
+ return prev;
+ }
+
+ size_t set_low_threshold(size_t new_threshold) {
+ assert(_support_low_threshold, "can only be set if supported");
+ assert(new_threshold <= _high_threshold, "new_threshold must be <= _high_threshold");
+ size_t prev = _low_threshold;
+ _low_threshold = new_threshold;
+ return prev;
+ }
+};
+
+class SensorInfo : public CHeapObj {
+private:
+ instanceOop _sensor_obj;
+ bool _sensor_on;
+ size_t _sensor_count;
+
+ // before the actual sensor on flag and sensor count are set
+ // we maintain the number of pending triggers and clears.
+ // _pending_trigger_count means the number of pending triggers
+ // and the sensor count should be incremented by the same number.
+
+ int _pending_trigger_count;
+
+ // _pending_clear_count takes precedence if it's > 0 which
+ // indicates the resulting sensor will be off
+ // Sensor trigger requests will reset this clear count to
+ // indicate the resulting flag should be on.
+
+ int _pending_clear_count;
+
+ MemoryUsage _usage;
+
+ void clear(int count, TRAPS);
+ void trigger(int count, TRAPS);
+public:
+ SensorInfo();
+ void set_sensor(instanceOop sensor) {
+ assert(_sensor_obj == NULL, "Should be set only once");
+ _sensor_obj = sensor;
+ }
+
+ bool has_pending_requests() {
+ return (_pending_trigger_count > 0 || _pending_clear_count > 0);
+ }
+
+ int pending_trigger_count() { return _pending_trigger_count; }
+ int pending_clear_count() { return _pending_clear_count; }
+
+ // When this method is used, the memory usage is monitored
+ // as a gauge attribute. High and low thresholds are designed
+ // to provide a hysteresis mechanism to avoid repeated triggering
+ // of notifications when the attribute value makes small oscillations
+ // around the high or low threshold value.
+ //
+ // The sensor will be triggered if:
+ // (1) the usage is crossing above the high threshold and
+ // the sensor is currently off and no pending
+ // trigger requests; or
+ // (2) the usage is crossing above the high threshold and
+ // the sensor will be off (i.e. sensor is currently on
+ // and has pending clear requests).
+ //
+ // Subsequent crossings of the high threshold value do not cause
+ // any triggers unless the usage becomes less than the low threshold.
+ //
+ // The sensor will be cleared if:
+ // (1) the usage is crossing below the low threshold and
+ // the sensor is currently on and no pending
+ // clear requests; or
+ // (2) the usage is crossing below the low threshold and
+ // the sensor will be on (i.e. sensor is currently off
+ // and has pending trigger requests).
+ //
+ // Subsequent crossings of the low threshold value do not cause
+ // any clears unless the usage becomes greater than or equal
+ // to the high threshold.
+ //
+ // If the current level is between high and low threhsold, no change.
+ //
+ void set_gauge_sensor_level(MemoryUsage usage, ThresholdSupport* high_low_threshold);
+
+ // When this method is used, the memory usage is monitored as a
+ // simple counter attribute. The sensor will be triggered
+ // whenever the usage is crossing the threshold to keep track
+ // of the number of times the VM detects such a condition occurs.
+ //
+ // The sensor will be triggered if:
+ // - the usage is crossing above the high threshold regardless
+ // of the current sensor state.
+ //
+ // The sensor will be cleared if:
+ // (1) the usage is crossing below the low threshold and
+ // the sensor is currently on; or
+ // (2) the usage is crossing below the low threshold and
+ // the sensor will be on (i.e. sensor is currently off
+ // and has pending trigger requests).
+ //
+ void set_counter_sensor_level(MemoryUsage usage, ThresholdSupport* counter_threshold);
+
+ void process_pending_requests(TRAPS);
+ void oops_do(OopClosure* f);
+
+#ifndef PRODUCT
+ // printing on default output stream;
+ void print();
+#endif // PRODUCT
+};
+
+class LowMemoryDetector : public AllStatic {
+friend class LowMemoryDetectorDisabler;
+private:
+ // true if any collected heap has low memory detection enabled
+ static volatile bool _enabled_for_collected_pools;
+ // > 0 if temporary disabed
+ static volatile jint _disabled_count;
+
+ static LowMemoryDetectorThread* _detector_thread;
+ static void low_memory_detector_thread_entry(JavaThread* thread, TRAPS);
+ static void check_memory_usage();
+ static bool has_pending_requests();
+ static bool temporary_disabled() { return _disabled_count > 0; }
+ static void disable() { Atomic::inc(&_disabled_count); }
+ static void enable() { Atomic::dec(&_disabled_count); }
+
+public:
+ static void initialize();
+ static void detect_low_memory();
+ static void detect_low_memory(MemoryPool* pool);
+ static void detect_after_gc_memory(MemoryPool* pool);
+
+ static bool is_enabled(MemoryPool* pool) {
+ // low memory detection is enabled for collected memory pools
+ // iff one of the collected memory pool has a sensor and the
+ // threshold set non-zero
+ if (pool->usage_sensor() == NULL) {
+ return false;
+ } else {
+ ThresholdSupport* threshold_support = pool->usage_threshold();
+ return (threshold_support->is_high_threshold_supported() ?
+ (threshold_support->high_threshold() > 0) : false);
+ }
+ }
+
+ // indicates if low memory detection is enabled for any collected
+ // memory pools
+ static inline bool is_enabled_for_collected_pools() {
+ return !temporary_disabled() && _enabled_for_collected_pools;
+ }
+
+ // recompute enabled flag
+ static void recompute_enabled_for_collected_pools();
+
+ // low memory detection for collected memory pools.
+ static inline void detect_low_memory_for_collected_pools() {
+ // no-op if low memory detection not enabled
+ if (!is_enabled_for_collected_pools()) {
+ return;
+ }
+ int num_memory_pools = MemoryService::num_memory_pools();
+ for (int i=0; i<num_memory_pools; i++) {
+ MemoryPool* pool = MemoryService::get_memory_pool(i);
+
+ // if low memory detection is enabled then check if the
+ // current used exceeds the high threshold
+ if (pool->is_collected_pool() && is_enabled(pool)) {
+ size_t used = pool->used_in_bytes();
+ size_t high = pool->usage_threshold()->high_threshold();
+ if (used > high) {
+ detect_low_memory(pool);
+ }
+ }
+ }
+ }
+
+};
+
+class LowMemoryDetectorDisabler: public StackObj {
+public:
+ LowMemoryDetectorDisabler()
+ {
+ LowMemoryDetector::disable();
+ }
+ ~LowMemoryDetectorDisabler()
+ {
+ assert(LowMemoryDetector::temporary_disabled(), "should be disabled!");
+ LowMemoryDetector::enable();
+ }
+};