org.metafacture.triples.MemoryWarningSystem Maven / Gradle / Ivy
/*
* Copyright 2016 Christoph Böhme
*
* Licensed under the Apache License, Version 2.0 the "License";
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Code based on http://www.javaspecialists.eu/archive/Issue092.html
*/
package org.metafacture.triples;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryNotificationInfo;
import java.lang.management.MemoryPoolMXBean;
import java.lang.management.MemoryType;
import java.util.Collection;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.management.Notification;
import javax.management.NotificationEmitter;
import javax.management.NotificationListener;
/**
* This memory warning system will call the listener when we exceed the
* percentage of available memory specified. The class is static, since the
* usage threshold can only be set to one number.
*/
final class MemoryWarningSystem {
private static final MemoryPoolMXBean TENURED_GEN_POOL = findTenuredGenPool();
private static final double DEFAULT_THRESHOLD = 0.8;
private static final Collection LISTENERS = new CopyOnWriteArrayList();
private MemoryWarningSystem() {
// no instances
}
static {
setUsageThreshold(DEFAULT_THRESHOLD);
final MemoryMXBean mbean = ManagementFactory.getMemoryMXBean();
final NotificationEmitter emitter = (NotificationEmitter) mbean;
emitter.addNotificationListener(new NotificationListener() {
@Override
public void handleNotification(final Notification notification, final Object handback) {
if (notification.getType().equals(MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED)) {
for (final Listener listener : getListeners()) {
listener.memoryLow(getUsedMemory(), getMaxMemory());
}
}
}
}, null, null);
}
private static Collection getListeners() {
return LISTENERS;
}
private static long getMaxMemory() {
return TENURED_GEN_POOL.getUsage().getMax();
}
private static long getUsedMemory() {
return TENURED_GEN_POOL.getUsage().getUsed();
}
static boolean addListener(final Listener listener) {
return LISTENERS.add(listener);
}
static boolean removeListener(final Listener listener) {
return LISTENERS.remove(listener);
}
private static void setUsageThreshold(final double threshold) {
if (threshold <= 0.0 || threshold > 1.0) {
throw new IllegalArgumentException("'threshold' must be in [0.0, 1.0]");
}
TENURED_GEN_POOL.setUsageThreshold((long) (getMaxMemory() * threshold));
}
/**
* Tenured Space Pool can be determined by it being of type HEAP and by it
* being possible to set the usage threshold.
*
* @return MXBean for the Tenured Space Pool
*/
private static MemoryPoolMXBean findTenuredGenPool() {
// I don't know whether this approach is better, or whether
// we should rather check for the pool name "Tenured Gen"?
for (final MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) {
if (pool.getType() == MemoryType.HEAP && pool.isUsageThresholdSupported()) {
return pool;
}
}
throw new AssertionError("Could not find tenured space");
}
/**
* Interface for low memory listeners
*/
interface Listener {
void memoryLow(long usedMemory, long maxMemory);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy