Set a maximum perm gen space usage for our background compiler.
Dieser Commit ist enthalten in:
Ursprung
0a3c1b13ed
Commit
b8b39b4785
@ -7,12 +7,6 @@
|
|||||||
</attributes>
|
</attributes>
|
||||||
</classpathentry>
|
</classpathentry>
|
||||||
<classpathentry combineaccessrules="false" kind="src" path="/ProtocolLib"/>
|
<classpathentry combineaccessrules="false" kind="src" path="/ProtocolLib"/>
|
||||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
|
|
||||||
<attributes>
|
|
||||||
<attribute name="optional" value="true"/>
|
|
||||||
<attribute name="maven.pomderived" value="true"/>
|
|
||||||
</attributes>
|
|
||||||
</classpathentry>
|
|
||||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6">
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6">
|
||||||
<attributes>
|
<attributes>
|
||||||
<attribute name="maven.pomderived" value="true"/>
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
|
@ -17,6 +17,10 @@
|
|||||||
|
|
||||||
package com.comphenix.protocol.reflect.compiler;
|
package com.comphenix.protocol.reflect.compiler;
|
||||||
|
|
||||||
|
import java.lang.management.ManagementFactory;
|
||||||
|
import java.lang.management.MemoryPoolMXBean;
|
||||||
|
import java.lang.management.MemoryUsage;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
@ -29,6 +33,9 @@ import javax.annotation.Nullable;
|
|||||||
|
|
||||||
import com.comphenix.protocol.error.ErrorReporter;
|
import com.comphenix.protocol.error.ErrorReporter;
|
||||||
import com.comphenix.protocol.reflect.StructureModifier;
|
import com.comphenix.protocol.reflect.StructureModifier;
|
||||||
|
import com.comphenix.protocol.reflect.compiler.StructureCompiler.StructureKey;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -48,9 +55,18 @@ public class BackgroundCompiler {
|
|||||||
// How long to wait for a shutdown
|
// How long to wait for a shutdown
|
||||||
public static final int SHUTDOWN_DELAY_MS = 2000;
|
public static final int SHUTDOWN_DELAY_MS = 2000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default fraction of perm gen space after which the background compiler will be disabled.
|
||||||
|
*/
|
||||||
|
public static final double DEFAULT_DISABLE_AT_PERM_GEN = 0.65;
|
||||||
|
|
||||||
// The single background compiler we're using
|
// The single background compiler we're using
|
||||||
private static BackgroundCompiler backgroundCompiler;
|
private static BackgroundCompiler backgroundCompiler;
|
||||||
|
|
||||||
|
// Classes we're currently compiling
|
||||||
|
private Map<StructureKey, List<CompileListener<?>>> listeners = Maps.newHashMap();
|
||||||
|
private Object listenerLock = new Object();
|
||||||
|
|
||||||
private StructureCompiler compiler;
|
private StructureCompiler compiler;
|
||||||
private boolean enabled;
|
private boolean enabled;
|
||||||
private boolean shuttingDown;
|
private boolean shuttingDown;
|
||||||
@ -58,6 +74,8 @@ public class BackgroundCompiler {
|
|||||||
private ExecutorService executor;
|
private ExecutorService executor;
|
||||||
private ErrorReporter reporter;
|
private ErrorReporter reporter;
|
||||||
|
|
||||||
|
private double disablePermGenFraction = DEFAULT_DISABLE_AT_PERM_GEN;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the current background compiler.
|
* Retrieves the current background compiler.
|
||||||
* @return Current background compiler.
|
* @return Current background compiler.
|
||||||
@ -139,25 +157,60 @@ public class BackgroundCompiler {
|
|||||||
* @param uncompiled - structure modifier to compile.
|
* @param uncompiled - structure modifier to compile.
|
||||||
* @param listener - listener responsible for responding to the compilation.
|
* @param listener - listener responsible for responding to the compilation.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
public <TKey> void scheduleCompilation(final StructureModifier<TKey> uncompiled, final CompileListener<TKey> listener) {
|
public <TKey> void scheduleCompilation(final StructureModifier<TKey> uncompiled, final CompileListener<TKey> listener) {
|
||||||
|
|
||||||
// Only schedule if we're enabled
|
// Only schedule if we're enabled
|
||||||
if (enabled && !shuttingDown) {
|
if (enabled && !shuttingDown) {
|
||||||
|
// Check perm gen
|
||||||
|
if (getPermGenUsage() > disablePermGenFraction)
|
||||||
|
return;
|
||||||
|
|
||||||
// Don't try to schedule anything
|
// Don't try to schedule anything
|
||||||
if (executor == null || executor.isShutdown())
|
if (executor == null || executor.isShutdown())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Use to look up structure modifiers
|
||||||
|
final StructureKey key = new StructureKey(uncompiled);
|
||||||
|
|
||||||
|
// Allow others to listen in too
|
||||||
|
synchronized (listenerLock) {
|
||||||
|
List list = listeners.get(key);
|
||||||
|
|
||||||
|
if (!listeners.containsKey(key)) {
|
||||||
|
listeners.put(key, (List) Lists.newArrayList(listener));
|
||||||
|
} else {
|
||||||
|
// We're currently compiling
|
||||||
|
list.add(listener);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create the worker that will compile our modifier
|
// Create the worker that will compile our modifier
|
||||||
Callable<?> worker = new Callable<Object>() {
|
Callable<?> worker = new Callable<Object>() {
|
||||||
@Override
|
@Override
|
||||||
public Object call() throws Exception {
|
public Object call() throws Exception {
|
||||||
StructureModifier<TKey> modifier = uncompiled;
|
StructureModifier<TKey> modifier = uncompiled;
|
||||||
|
List list = null;
|
||||||
|
|
||||||
// Do our compilation
|
// Do our compilation
|
||||||
try {
|
try {
|
||||||
modifier = compiler.compile(modifier);
|
modifier = compiler.compile(modifier);
|
||||||
listener.onCompiled(modifier);
|
|
||||||
|
synchronized (listenerLock) {
|
||||||
|
list = listeners.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only execute the listeners if there is a list
|
||||||
|
if (list != null) {
|
||||||
|
for (Object compileListener : list) {
|
||||||
|
((CompileListener<TKey>) compileListener).onCompiled(modifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove it when we're done
|
||||||
|
synchronized (listenerLock) {
|
||||||
|
list = listeners.remove(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
// Disable future compilations!
|
// Disable future compilations!
|
||||||
@ -205,6 +258,41 @@ public class BackgroundCompiler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a compile listener if we are still waiting for the structure modifier to be compiled.
|
||||||
|
* @param uncompiled - the structure modifier that may get compiled.
|
||||||
|
* @param listener - the listener to invoke in that case.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <TKey> void addListener(final StructureModifier<TKey> uncompiled, final CompileListener<TKey> listener) {
|
||||||
|
synchronized (listenerLock) {
|
||||||
|
StructureKey key = new StructureKey(uncompiled);
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
List list = listeners.get(key);
|
||||||
|
|
||||||
|
if (list != null) {
|
||||||
|
list.add(listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the current usage of the Perm Gen space in percentage.
|
||||||
|
* @return Usage of the perm gen space.
|
||||||
|
*/
|
||||||
|
private double getPermGenUsage() {
|
||||||
|
for (MemoryPoolMXBean item : ManagementFactory.getMemoryPoolMXBeans()) {
|
||||||
|
if (item.getName().contains("Perm Gen")) {
|
||||||
|
MemoryUsage usage = item.getUsage();
|
||||||
|
return usage.getUsed() / (double) usage.getCommitted();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unknown
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clean up after ourselves using the default timeout.
|
* Clean up after ourselves using the default timeout.
|
||||||
*/
|
*/
|
||||||
@ -246,6 +334,22 @@ public class BackgroundCompiler {
|
|||||||
this.enabled = enabled;
|
this.enabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the fraction of perm gen space used after which the background compiler will be disabled.
|
||||||
|
* @return The fraction after which the background compiler is disabled.
|
||||||
|
*/
|
||||||
|
public double getDisablePermGenFraction() {
|
||||||
|
return disablePermGenFraction;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the fraction of perm gen space used after which the background compiler will be disabled.
|
||||||
|
* @param fraction - the maximum use of perm gen space.
|
||||||
|
*/
|
||||||
|
public void setDisablePermGenFraction(double fraction) {
|
||||||
|
this.disablePermGenFraction = fraction;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the current structure compiler.
|
* Retrieve the current structure compiler.
|
||||||
* @return Current structure compiler.
|
* @return Current structure compiler.
|
||||||
|
@ -95,7 +95,7 @@ public final class StructureCompiler {
|
|||||||
|
|
||||||
// Used to store generated classes of different types
|
// Used to store generated classes of different types
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
private static class StructureKey {
|
static class StructureKey {
|
||||||
private Class targetType;
|
private Class targetType;
|
||||||
private Class fieldType;
|
private Class fieldType;
|
||||||
|
|
||||||
|
In neuem Issue referenzieren
Einen Benutzer sperren