J'aimerais savoir comment provoquer une OutOfMemoryError : Metaspace par vous-même ? Est-il possible de charger un grand nombre de classes et de les faire rester en mémoire pendant un long moment.
Réponses
Trop de publicités?Il suffit d'ajouter du texte à un StringBuilder
jusqu'à ce que vous obteniez OutOfMemoryError
StringBuilder s = new StringBuilder();
while (true) {
s.append("dummy");
}
Vous pouvez également ajouter une classe fictive à un fichier de type List
ou un Set
mais la création de nouvelles instances prend plus de temps et vous devrez attendre un certain temps avant d'obtenir des résultats. OutOfMemoryError
.
Le coût en temps amorti de l'insertion dans une liste Array fera également la différence.
Mise à jour de
Par défaut, Java 8 dispose d'une taille maximale illimitée pour Metaspace, donc tant que vous ne fixez pas la limite en utilisant l'attribut MaxMetaspaceSize
l'erreur ne doit pas être déclenchée.
Pour créer OutOfMemoryError: Metaspace
utiliser le javassist.ClassPool
bibliothèque. L'exemple ci-dessous créera la bibliothèque Metaspace
erreur.
import javassist.ClassPool;
public class OutOfMemoryErrorMetaspace {
//ClassPool objects hold all the CtClasses.
static ClassPool classPool = ClassPool.getDefault();
public static void main(String[] args) throws Exception {
for (int i = 0; i < 1000000; i++) {
//makeClass method - Creates a new class (or interface) from the given class file.
Class clas = classPool.makeClass(
i + " outofmemory.OutOfMemoryErrorMetaspace ").toClass();
//Print name of class loaded
System.out.println(clas.getName());
}
}
}
Afin de simuler java.lang.OutOfMemoryError: Metaspace
vous devez charger un grand nombre de classes différentes.
Tout d'abord, les paramètres suivants du méta-espace doivent être définis :
-XX:MaxMetaspaceSize=10m
-XX:MetaspaceSize=2M
-XX:MaxMetaspaceFreeRatio=1
-XX:MaxMetaspaceExpansion=1K
-XX:MinMetaspaceFreeRatio=1
-XX:InitialBootClassLoaderMetaspaceSize=2M
Ensuite, le code suivant permet au classloader de charger un grand nombre de classes différentes. Ceci est accompli en prenant le bytecode compilé d'une classe mypackage.Myclass0
et d'ajuster pour créer itérativement de nouvelles classes en changeant le nom de la classe et en ajustant la longueur du nom de la classe :
public static void main(String[] args) throws Exception {
String clazzBase64 ="yv66vgAAADcADAEAEm15cGFja2FnZS9NeWNsYXNzMAcAAQEAEGphdmEvbGFuZy9PYmplY3QHAAMBAApTb3VyY2VGaWxlAQANTXljbGFzczAuamF2YQEABjxpbml0PgEAAygpVgwABwAICgAEAAkBAARDb2RlACEAAgAEAAAAAAABAAEABwAIAAEACwAAABEAAQABAAAABSq3AAqxAAAAAAABAAUAAAACAAY=";
byte[] compiledClazz = Base64.getDecoder().decode(clazzBase64);
int classNameLength = Integer.valueOf(compiledClazz[12]);
MyClassLoader myClassLoader = new MyClassLoader(Thread.currentThread().getContextClassLoader());
for (int i = 0; ; i++) {
byte[] bytes = String.valueOf(i).getBytes();
byte[] bytecode = new byte[compiledClazz.length + bytes.length - 1];
System.arraycopy(compiledClazz, 0, bytecode, 0, 30);
bytecode[12] = (byte) (classNameLength + bytes.length - 1 & 0xFF);
System.arraycopy(bytes, 0, bytecode, 30, bytes.length);
System.arraycopy(compiledClazz, 31, bytecode, 30 + bytes.length, compiledClazz.length - 31);
String classname = "mypackage.Myclass" + i;
Class c = myClassLoader.getClass(classname, bytecode);
}
}
public static class MyClassLoader extends ClassLoader {
public MyClassLoader(ClassLoader parent) {
super(parent);
}
public Class<?> getClass(String name, byte[] code) {
return defineClass(name, code, 0, code.length);
}
}