1 /*
2 * Copyright (c) 2017 SAP SE. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 /**
25 * @test
26 * @bug 8173743
27 * @requires vm.compMode != "Xcomp"
28 * @summary Failures during class definition can lead to memory leaks in metaspace
29 * @library /test/lib
30 * @run main/othervm test.DefineClass defineClass
31 * @run main/othervm test.DefineClass defineSystemClass
32 * @run main/othervm -XX:+UnlockDiagnosticVMOptions
33 -XX:+UnsyncloadClass -XX:+AllowParallelDefineClass
34 test.DefineClass defineClassParallel
35 * @run main/othervm -XX:+UnlockDiagnosticVMOptions
36 -XX:+UnsyncloadClass -XX:-AllowParallelDefineClass
37 test.DefineClass defineClassParallel
38 * @run main/othervm -XX:+UnlockDiagnosticVMOptions
39 -XX:-UnsyncloadClass -XX:+AllowParallelDefineClass
40 test.DefineClass defineClassParallel
41 * @run main/othervm -XX:+UnlockDiagnosticVMOptions
42 -XX:-UnsyncloadClass -XX:-AllowParallelDefineClass
43 test.DefineClass defineClassParallel
44 * @run main/othervm -Djdk.attach.allowAttachSelf test.DefineClass redefineClass
45 * @run main/othervm -Djdk.attach.allowAttachSelf test.DefineClass redefineClassWithError
46 * @author volker.simonis@gmail.com
47 */
48
49 package test;
50
51 import java.io.ByteArrayOutputStream;
52 import java.io.File;
53 import java.io.FileOutputStream;
54 import java.io.InputStream;
55 import java.lang.instrument.ClassDefinition;
56 import java.lang.instrument.Instrumentation;
57 import java.lang.management.ManagementFactory;
58 import java.util.Scanner;
59 import java.util.concurrent.CountDownLatch;
60 import java.util.jar.Attributes;
61 import java.util.jar.JarEntry;
62 import java.util.jar.JarOutputStream;
109 private byte[] buf;
110
111 public ParallelLoadingThread(MyParallelClassLoader pcl, byte[] buf, CountDownLatch stop) {
112 this.pcl = pcl;
113 this.stop = stop;
114 this.buf = buf;
115 }
116
117 public void run() {
118 try {
119 stop.await();
120 } catch (InterruptedException e) {
121 e.printStackTrace();
122 }
123 try {
124 @SuppressWarnings("unchecked")
125 Class<DefineClass> dc = (Class<DefineClass>) pcl.myDefineClass(DefineClass.class.getName(), buf, 0, buf.length);
126 }
127 catch (LinkageError jle) {
128 // Expected with a parallel capable class loader and
129 // -XX:+UnsyncloadClass or -XX:+AllowParallelDefineClass
130 pcl.incrementLinkageErrors();
131 }
132
133 }
134 }
135
136 static private class MyClassLoader extends ClassLoader {
137 public Class<?> myDefineClass(String name, byte[] b, int off, int len) throws ClassFormatError {
138 return defineClass(name, b, off, len, null);
139 }
140 }
141
142 static private class MyParallelClassLoader extends ClassLoader {
143 static {
144 System.out.println("parallelCapable : " + registerAsParallelCapable());
145 }
146 public Class<?> myDefineClass(String name, byte[] b, int off, int len) throws ClassFormatError {
147 return defineClass(name, b, off, len, null);
148 }
149 public synchronized void incrementLinkageErrors() {
303 System.gc();
304 System.out.println("System.gc()");
305 // At least after System.gc() the failed loading attempts should leave no instances around!
306 printClassStats(1, true);
307 }
308 else if ("defineClassParallel".equals(args[0])) {
309 MyParallelClassLoader pcl = new MyParallelClassLoader();
310 CountDownLatch stop = new CountDownLatch(1);
311
312 Thread[] threads = new Thread[iterations];
313 for (int i = 0; i < iterations; i++) {
314 (threads[i] = new ParallelLoadingThread(pcl, buf, stop)).start();
315 }
316 stop.countDown(); // start parallel class loading..
317 // ..and wait until all threads loaded the class
318 for (int i = 0; i < iterations; i++) {
319 threads[i].join();
320 }
321 System.out.print("Counted " + pcl.getLinkageErrors() + " LinkageErrors ");
322 System.out.println(pcl.getLinkageErrors() == 0 ?
323 "" : "(use -XX:+UnsyncloadClass and/or -XX:+AllowParallelDefineClass to avoid this)");
324 System.gc();
325 System.out.println("System.gc()");
326 // After System.gc() we expect to remain with two instances: one is the initial version which is
327 // kept alive by this main method and another one in the parallel class loader.
328 printClassStats(2, true);
329 }
330 else if ("redefineClass".equals(args[0])) {
331 loadInstrumentationAgent(myName, buf);
332 int index = getStringIndex("AAAAAAAA", buf);
333 CountDownLatch stop = new CountDownLatch(1);
334
335 Thread[] threads = new Thread[iterations];
336 for (int i = 0; i < iterations; i++) {
337 buf[index] = (byte) ('A' + i + 1); // Change string constant in getID() which is legal in redefinition
338 instrumentation.redefineClasses(new ClassDefinition(DefineClass.class, buf));
339 DefineClass dc = DefineClass.class.newInstance();
340 CountDownLatch start = new CountDownLatch(1);
341 (threads[i] = new MyThread(dc, start, stop)).start();
342 start.await(); // Wait until the new thread entered the getID() method
343 }
|
1 /*
2 * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
3 * Copyright (c) 2017 SAP SE. All rights reserved.
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 *
6 * This code is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 only, as
8 * published by the Free Software Foundation.
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 */
24
25 /**
26 * @test
27 * @bug 8173743
28 * @requires vm.compMode != "Xcomp"
29 * @summary Failures during class definition can lead to memory leaks in metaspace
30 * @library /test/lib
31 * @run main/othervm test.DefineClass defineClass
32 * @run main/othervm test.DefineClass defineSystemClass
33 * @run main/othervm -XX:+AllowParallelDefineClass
34 test.DefineClass defineClassParallel
35 * @run main/othervm -XX:-AllowParallelDefineClass
36 test.DefineClass defineClassParallel
37 * @run main/othervm -Djdk.attach.allowAttachSelf test.DefineClass redefineClass
38 * @run main/othervm -Djdk.attach.allowAttachSelf test.DefineClass redefineClassWithError
39 * @author volker.simonis@gmail.com
40 */
41
42 package test;
43
44 import java.io.ByteArrayOutputStream;
45 import java.io.File;
46 import java.io.FileOutputStream;
47 import java.io.InputStream;
48 import java.lang.instrument.ClassDefinition;
49 import java.lang.instrument.Instrumentation;
50 import java.lang.management.ManagementFactory;
51 import java.util.Scanner;
52 import java.util.concurrent.CountDownLatch;
53 import java.util.jar.Attributes;
54 import java.util.jar.JarEntry;
55 import java.util.jar.JarOutputStream;
102 private byte[] buf;
103
104 public ParallelLoadingThread(MyParallelClassLoader pcl, byte[] buf, CountDownLatch stop) {
105 this.pcl = pcl;
106 this.stop = stop;
107 this.buf = buf;
108 }
109
110 public void run() {
111 try {
112 stop.await();
113 } catch (InterruptedException e) {
114 e.printStackTrace();
115 }
116 try {
117 @SuppressWarnings("unchecked")
118 Class<DefineClass> dc = (Class<DefineClass>) pcl.myDefineClass(DefineClass.class.getName(), buf, 0, buf.length);
119 }
120 catch (LinkageError jle) {
121 // Expected with a parallel capable class loader and
122 // -XX:+AllowParallelDefineClass
123 pcl.incrementLinkageErrors();
124 }
125
126 }
127 }
128
129 static private class MyClassLoader extends ClassLoader {
130 public Class<?> myDefineClass(String name, byte[] b, int off, int len) throws ClassFormatError {
131 return defineClass(name, b, off, len, null);
132 }
133 }
134
135 static private class MyParallelClassLoader extends ClassLoader {
136 static {
137 System.out.println("parallelCapable : " + registerAsParallelCapable());
138 }
139 public Class<?> myDefineClass(String name, byte[] b, int off, int len) throws ClassFormatError {
140 return defineClass(name, b, off, len, null);
141 }
142 public synchronized void incrementLinkageErrors() {
296 System.gc();
297 System.out.println("System.gc()");
298 // At least after System.gc() the failed loading attempts should leave no instances around!
299 printClassStats(1, true);
300 }
301 else if ("defineClassParallel".equals(args[0])) {
302 MyParallelClassLoader pcl = new MyParallelClassLoader();
303 CountDownLatch stop = new CountDownLatch(1);
304
305 Thread[] threads = new Thread[iterations];
306 for (int i = 0; i < iterations; i++) {
307 (threads[i] = new ParallelLoadingThread(pcl, buf, stop)).start();
308 }
309 stop.countDown(); // start parallel class loading..
310 // ..and wait until all threads loaded the class
311 for (int i = 0; i < iterations; i++) {
312 threads[i].join();
313 }
314 System.out.print("Counted " + pcl.getLinkageErrors() + " LinkageErrors ");
315 System.out.println(pcl.getLinkageErrors() == 0 ?
316 "" : "(use -XX:+AllowParallelDefineClass to avoid this)");
317 System.gc();
318 System.out.println("System.gc()");
319 // After System.gc() we expect to remain with two instances: one is the initial version which is
320 // kept alive by this main method and another one in the parallel class loader.
321 printClassStats(2, true);
322 }
323 else if ("redefineClass".equals(args[0])) {
324 loadInstrumentationAgent(myName, buf);
325 int index = getStringIndex("AAAAAAAA", buf);
326 CountDownLatch stop = new CountDownLatch(1);
327
328 Thread[] threads = new Thread[iterations];
329 for (int i = 0; i < iterations; i++) {
330 buf[index] = (byte) ('A' + i + 1); // Change string constant in getID() which is legal in redefinition
331 instrumentation.redefineClasses(new ClassDefinition(DefineClass.class, buf));
332 DefineClass dc = DefineClass.class.newInstance();
333 CountDownLatch start = new CountDownLatch(1);
334 (threads[i] = new MyThread(dc, start, stop)).start();
335 start.await(); // Wait until the new thread entered the getID() method
336 }
|