001/* 002 * Copyright 2007 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.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/ecl2.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 */ 016package org.kuali.ole.sys; 017 018import java.lang.management.ManagementFactory; 019import java.lang.management.MemoryNotificationInfo; 020import java.lang.management.MemoryPoolMXBean; 021import java.lang.management.MemoryType; 022import java.util.ArrayList; 023import java.util.Arrays; 024import java.util.Collection; 025import java.util.HashMap; 026import java.util.Map; 027 028import javax.management.ListenerNotFoundException; 029import javax.management.Notification; 030import javax.management.NotificationEmitter; 031import javax.management.NotificationListener; 032 033import org.apache.log4j.Logger; 034 035public class MemoryMonitor { 036 private final Collection<Listener> listeners = new ArrayList<Listener>(); 037 private static final Logger LOG = Logger.getLogger(MemoryMonitor.class); 038 private String springContextId; 039 040 public interface Listener { 041 public void memoryUsageLow(String springContextId, Map<String, String> memoryUsageStatistics, String deadlockedThreadIds); 042 } 043 NotificationListener lowMemoryListener; 044 public MemoryMonitor() { 045 LOG.info("initializing"); 046 this.springContextId = "Unknown"; 047 ManagementFactory.getThreadMXBean().setThreadContentionMonitoringEnabled(true); 048 ManagementFactory.getThreadMXBean().setThreadCpuTimeEnabled(true); 049 lowMemoryListener = new NotificationListener() { 050 public void handleNotification(Notification n, Object hb) { 051 if (n.getType().equals(MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED)) { 052 Map<String, String> memoryUsageStatistics = new HashMap<String, String>(); 053 memoryUsageStatistics.put("MemoryMXBean: " + MemoryType.HEAP, ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().toString()); 054 memoryUsageStatistics.put("MemoryMXBean:" + MemoryType.NON_HEAP, ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage().toString()); 055 for (MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) { 056 memoryUsageStatistics.put("MemoryPoolMXBean: " + pool.getType(), pool.getUsage().toString()); 057 } 058 for (Listener listener : listeners) { 059 listener.memoryUsageLow(springContextId, memoryUsageStatistics, Arrays.toString(ManagementFactory.getThreadMXBean().findMonitorDeadlockedThreads())); 060 } 061 } 062 } 063 }; 064 ((NotificationEmitter) ManagementFactory.getMemoryMXBean()).addNotificationListener(lowMemoryListener, null, null); 065 } 066 067 public void stop() { 068 try { 069 removeAllListeners(); 070 ((NotificationEmitter) ManagementFactory.getMemoryMXBean()).removeNotificationListener(lowMemoryListener); 071 } catch (ListenerNotFoundException ex) { 072 LOG.error( "Unable to unregister mbean listener", ex); 073 } 074 } 075 076 public void removeAllListeners() { 077 listeners.clear(); 078 } 079 080 public MemoryMonitor(String springContextId) { 081 this(); 082 this.springContextId = springContextId; 083 } 084 085 public boolean addListener(Listener listener) { 086 return listeners.add(listener); 087 } 088 089 public boolean removeListener(Listener listener) { 090 return listeners.remove(listener); 091 } 092 093 public static void setPercentageUsageThreshold(double percentage) { 094 for (MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) { 095 if (pool.getType() == MemoryType.HEAP && pool.isUsageThresholdSupported()) { 096 if (percentage <= 0.0 || percentage > 1.0) { 097 throw new IllegalArgumentException("percentage not in range"); 098 } 099 long warningThreshold = (long) (pool.getUsage().getMax() * percentage); 100 pool.setUsageThreshold(warningThreshold); 101 } 102 } 103 } 104}