/* * The Kuali Financial System, a comprehensive financial management system for higher education. * * Copyright 2005-2014 The Kuali Foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.kuali.kfs.sys; import java.lang.management.ManagementFactory; import java.lang.management.MemoryNotificationInfo; import java.lang.management.MemoryPoolMXBean; import java.lang.management.MemoryType; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Map; import javax.management.ListenerNotFoundException; import javax.management.Notification; import javax.management.NotificationEmitter; import javax.management.NotificationListener; import org.apache.log4j.Logger; public class MemoryMonitor { private final Collection<Listener> listeners = new ArrayList<Listener>(); private static final Logger LOG = Logger.getLogger(MemoryMonitor.class); private String springContextId; public interface Listener { public void memoryUsageLow(String springContextId, Map<String, String> memoryUsageStatistics, String deadlockedThreadIds); } NotificationListener lowMemoryListener; public MemoryMonitor() { LOG.info("initializing"); this.springContextId = "Unknown"; ManagementFactory.getThreadMXBean().setThreadContentionMonitoringEnabled(true); ManagementFactory.getThreadMXBean().setThreadCpuTimeEnabled(true); lowMemoryListener = new NotificationListener() { public void handleNotification(Notification n, Object hb) { if (n.getType().equals(MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED)) { Map<String, String> memoryUsageStatistics = new HashMap<String, String>(); memoryUsageStatistics.put("MemoryMXBean: " + MemoryType.HEAP, ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().toString()); memoryUsageStatistics.put("MemoryMXBean:" + MemoryType.NON_HEAP, ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage().toString()); for (MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) { memoryUsageStatistics.put("MemoryPoolMXBean: " + pool.getType(), pool.getUsage().toString()); } for (Listener listener : listeners) { listener.memoryUsageLow(springContextId, memoryUsageStatistics, Arrays.toString(ManagementFactory.getThreadMXBean().findMonitorDeadlockedThreads())); } } } }; ((NotificationEmitter) ManagementFactory.getMemoryMXBean()).addNotificationListener(lowMemoryListener, null, null); } public void stop() { try { removeAllListeners(); ((NotificationEmitter) ManagementFactory.getMemoryMXBean()).removeNotificationListener(lowMemoryListener); } catch (ListenerNotFoundException ex) { LOG.error( "Unable to unregister mbean listener", ex); } } public void removeAllListeners() { listeners.clear(); } public MemoryMonitor(String springContextId) { this(); this.springContextId = springContextId; } public boolean addListener(Listener listener) { return listeners.add(listener); } public boolean removeListener(Listener listener) { return listeners.remove(listener); } public static void setPercentageUsageThreshold(double percentage) { for (MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) { if (pool.getType() == MemoryType.HEAP && pool.isUsageThresholdSupported()) { if (percentage <= 0.0 || percentage > 1.0) { throw new IllegalArgumentException("percentage not in range"); } long warningThreshold = (long) (pool.getUsage().getMax() * percentage); pool.setUsageThreshold(warningThreshold); } } } }