001: /*
002: * Copyright 2007 The Kuali Foundation.
003: *
004: * Licensed under the Educational Community License, Version 1.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.opensource.org/licenses/ecl1.php
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.kuali.kfs.util;
017:
018: import java.lang.management.ManagementFactory;
019: import java.lang.management.MemoryNotificationInfo;
020: import java.lang.management.MemoryPoolMXBean;
021: import java.lang.management.MemoryType;
022: import java.util.ArrayList;
023: import java.util.Arrays;
024: import java.util.Collection;
025: import java.util.HashMap;
026: import java.util.Map;
027:
028: import javax.management.Notification;
029: import javax.management.NotificationEmitter;
030: import javax.management.NotificationListener;
031:
032: import org.apache.log4j.Logger;
033:
034: public class MemoryMonitor {
035: private final Collection<Listener> listeners = new ArrayList<Listener>();
036: private static final Logger LOG = Logger
037: .getLogger(MemoryMonitor.class);
038: private String springContextId;
039:
040: public interface Listener {
041: public void memoryUsageLow(String springContextId,
042: Map<String, String> memoryUsageStatistics,
043: String deadlockedThreadIds);
044: }
045:
046: public MemoryMonitor() {
047: LOG.info("initializing");
048: this .springContextId = "Unknown";
049: ManagementFactory.getThreadMXBean()
050: .setThreadContentionMonitoringEnabled(true);
051: ManagementFactory.getThreadMXBean().setThreadCpuTimeEnabled(
052: true);
053: ((NotificationEmitter) ManagementFactory.getMemoryMXBean())
054: .addNotificationListener(new NotificationListener() {
055: public void handleNotification(Notification n,
056: Object hb) {
057: if (n
058: .getType()
059: .equals(
060: MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED)) {
061: Map<String, String> memoryUsageStatistics = new HashMap<String, String>();
062: memoryUsageStatistics.put("MemoryMXBean: "
063: + MemoryType.HEAP,
064: ManagementFactory.getMemoryMXBean()
065: .getHeapMemoryUsage()
066: .toString());
067: memoryUsageStatistics.put("MemoryMXBean:"
068: + MemoryType.NON_HEAP,
069: ManagementFactory.getMemoryMXBean()
070: .getNonHeapMemoryUsage()
071: .toString());
072: for (MemoryPoolMXBean pool : ManagementFactory
073: .getMemoryPoolMXBeans()) {
074: memoryUsageStatistics.put(
075: "MemoryPoolMXBean: "
076: + pool.getType(), pool
077: .getUsage().toString());
078: }
079: for (Listener listener : listeners) {
080: listener
081: .memoryUsageLow(
082: springContextId,
083: memoryUsageStatistics,
084: Arrays
085: .toString(ManagementFactory
086: .getThreadMXBean()
087: .findMonitorDeadlockedThreads()));
088: }
089: }
090: }
091: }, null, null);
092: }
093:
094: public MemoryMonitor(String springContextId) {
095: this ();
096: this .springContextId = springContextId;
097: }
098:
099: public boolean addListener(Listener listener) {
100: return listeners.add(listener);
101: }
102:
103: public boolean removeListener(Listener listener) {
104: return listeners.remove(listener);
105: }
106:
107: public static void setPercentageUsageThreshold(double percentage) {
108: for (MemoryPoolMXBean pool : ManagementFactory
109: .getMemoryPoolMXBeans()) {
110: if (pool.getType() == MemoryType.HEAP
111: && pool.isUsageThresholdSupported()) {
112: if (percentage <= 0.0 || percentage > 1.0) {
113: throw new IllegalArgumentException(
114: "percentage not in range");
115: }
116: long warningThreshold = (long) (pool.getUsage()
117: .getMax() * percentage);
118: pool.setUsageThreshold(warningThreshold);
119: }
120: }
121: }
122: }
|