1 /*
2 * Copyright (c) 2014, 2017, Oracle and/or its affiliates. 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 * @summary Test of diagnostic command VM.classloader_stats
27 * @library /test/lib
28 * @modules java.base/jdk.internal.misc
29 * java.compiler
30 * java.management
31 * jdk.internal.jvmstat/sun.jvmstat.monitor
32 * @run testng ClassLoaderStatsTest
33 */
34
35 import org.testng.annotations.Test;
36 import org.testng.Assert;
37
38 import jdk.test.lib.process.OutputAnalyzer;
39 import jdk.test.lib.dcmd.CommandExecutor;
40 import jdk.test.lib.dcmd.JMXExecutor;
41
42 import java.io.File;
43 import java.io.FileInputStream;
44 import java.io.IOException;
45 import java.nio.ByteBuffer;
46 import java.nio.channels.FileChannel;
47 import java.util.Iterator;
48 import java.util.regex.Matcher;
49 import java.util.regex.Pattern;
50
51 public class ClassLoaderStatsTest {
52
53 // ClassLoader Parent CLD* Classes ChunkSz BlockSz Type
54 // 0x00000007c0215928 0x0000000000000000 0x0000000000000000 0 0 0 org.eclipse.osgi.baseadaptor.BaseAdaptor$1
55 // 0x00000007c0009868 0x0000000000000000 0x00007fc52aebcc80 1 6144 3768 sun.reflect.DelegatingClassLoader
56 // 0x00000007c0009868 0x0000000000000000 0x00007fc52b8916d0 1 6144 3688 sun.reflect.DelegatingClassLoader
57 // 0x00000007c0009868 0x00000007c0038ba8 0x00007fc52afb8760 1 6144 3688 sun.reflect.DelegatingClassLoader
58 // 0x00000007c0009868 0x0000000000000000 0x00007fc52afbb1a0 1 6144 3688 sun.reflect.DelegatingClassLoader
59 // 0x0000000000000000 0x0000000000000000 0x00007fc523416070 5019 30060544 29956216 <boot classloader>
60 // 455 1210368 672848 + unsafe anonymous classes
61 // 0x00000007c016b5c8 0x00000007c0038ba8 0x00007fc52a995000 5 8192 5864 org.netbeans.StandardModule$OneModuleClassLoader
62 // 0x00000007c0009868 0x00000007c016b5c8 0x00007fc52ac13640 1 6144 3896 sun.reflect.DelegatingClassLoader
63 // ...
64
65 static Pattern clLine = Pattern.compile("0x\\p{XDigit}*\\s*0x\\p{XDigit}*\\s*0x\\p{XDigit}*\\s*(\\d*)\\s*(\\d*)\\s*(\\d*)\\s*(.*)");
66 static Pattern anonLine = Pattern.compile("\\s*(\\d*)\\s*(\\d*)\\s*(\\d*)\\s*.*");
67
68 public static DummyClassLoader dummyloader;
69
70 public void run(CommandExecutor executor) throws ClassNotFoundException {
71
72 // create a classloader and load our special class
73 dummyloader = new DummyClassLoader();
74 Class<?> c = Class.forName("TestClass", true, dummyloader);
75 if (c.getClassLoader() != dummyloader) {
76 Assert.fail("TestClass defined by wrong classloader: " + c.getClassLoader());
77 }
78
79 OutputAnalyzer output = executor.execute("VM.classloader_stats");
80 Iterator<String> lines = output.asLines().iterator();
81 while (lines.hasNext()) {
82 String line = lines.next();
83 Matcher m = clLine.matcher(line);
84 if (m.matches()) {
85 // verify that DummyClassLoader has loaded 1 class and 1 anonymous class
86 if (m.group(4).equals("ClassLoaderStatsTest$DummyClassLoader")) {
87 System.out.println("line: " + line);
88 if (!m.group(1).equals("1")) {
89 Assert.fail("Should have loaded 1 class: " + line);
90 }
91 checkPositiveInt(m.group(2));
92 checkPositiveInt(m.group(3));
93
94 String next = lines.next();
95 System.out.println("next: " + next);
96 Matcher m1 = anonLine.matcher(next);
97 m1.matches();
98 if (!m1.group(1).equals("1")) {
99 Assert.fail("Should have loaded 1 anonymous class, but found : " + m1.group(1));
100 }
101 checkPositiveInt(m1.group(2));
102 checkPositiveInt(m1.group(3));
103 }
104 }
105 }
106 }
107
108 private static void checkPositiveInt(String s) {
109 if (Integer.parseInt(s) <= 0) {
110 Assert.fail("Value should have been > 0: " + s);
111 }
112 }
113
114 public static class DummyClassLoader extends ClassLoader {
115
116 public static final String CLASS_NAME = "TestClass";
117
118 static ByteBuffer readClassFile(String name)
119 {
120 File f = new File(System.getProperty("test.classes", "."),
121 name);
122 try (FileInputStream fin = new FileInputStream(f);
123 FileChannel fc = fin.getChannel())
124 {
125 return fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
126 } catch (IOException e) {
127 Assert.fail("Can't open file: " + name, e);
128 }
129
130 /* Will not reach here as Assert.fail() throws exception */
131 return null;
132 }
133
134 protected Class<?> loadClass(String name, boolean resolve)
135 throws ClassNotFoundException
136 {
137 Class<?> c;
138 if (!"TestClass".equals(name)) {
139 c = super.loadClass(name, resolve);
140 } else {
141 // should not delegate to the system class loader
146 }
147 return c;
148 }
149
150 protected Class<?> findClass(String name)
151 throws ClassNotFoundException
152 {
153 if (!"TestClass".equals(name)) {
154 throw new ClassNotFoundException("Unexpected class: " + name);
155 }
156 return defineClass(name, readClassFile(name + ".class"), null);
157 }
158 } /* DummyClassLoader */
159
160 @Test
161 public void jmx() throws ClassNotFoundException {
162 run(new JMXExecutor());
163 }
164 }
165
166 class TestClass {
167 static {
168 // force creation of anonymous class (for the lambdaform)
169 Runnable r = () -> System.out.println("Hello");
170 r.run();
171 }
172 }
|
1 /*
2 * Copyright (c) 2014, 2020, Oracle and/or its affiliates. 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 * @summary Test of diagnostic command VM.classloader_stats
27 * @library /test/lib
28 * @modules java.base/jdk.internal.misc
29 * java.compiler
30 * java.management
31 * jdk.internal.jvmstat/sun.jvmstat.monitor
32 * @run testng/othervm --add-exports=java.base/jdk.internal.misc=ALL-UNNAMED --add-exports=jdk.internal.jvmstat/sun.jvmstat.monitor=ALL-UNNAMED ClassLoaderStatsTest
33 */
34
35 import org.testng.annotations.Test;
36 import org.testng.Assert;
37
38 import jdk.test.lib.process.OutputAnalyzer;
39 import jdk.test.lib.dcmd.CommandExecutor;
40 import jdk.test.lib.dcmd.JMXExecutor;
41
42 import java.io.ByteArrayOutputStream;
43 import java.io.File;
44 import java.io.FileInputStream;
45 import java.io.IOException;
46 import java.lang.invoke.MethodHandles;
47 import java.lang.invoke.MethodHandles.Lookup;
48 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*;
49 import java.nio.ByteBuffer;
50 import java.nio.channels.FileChannel;
51 import java.nio.file.Path;
52 import java.nio.file.Paths;
53 import java.util.Iterator;
54 import java.util.regex.Matcher;
55 import java.util.regex.Pattern;
56
57 import jdk.internal.misc.Unsafe;
58
59 public class ClassLoaderStatsTest {
60
61 // Expected output from VM.classloader_stats:
62 // ClassLoader Parent CLD* Classes ChunkSz BlockSz Type
63 // 0x0000000800bd3830 0x000000080037f468 0x00007f001c2ea170 1 10240 4672 ClassLoaderStatsTest$DummyClassLoader
64 // 1 2048 1080 + unsafe anonymous classes
65 // 1 2048 1088 + hidden weak classes
66 // 0x0000000000000000 0x0000000000000000 0x00007f00e852d190 1607 4628480 3931216 <boot class loader>
67 // 38 124928 85856 + hidden weak classes
68 // 0x00000008003b5508 0x0000000000000000 0x00007f001c2d4760 1 6144 4040 jdk.internal.reflect.DelegatingClassLoader
69 // 0x000000080037f468 0x000000080037ee80 0x00007f00e868e3f0 228 1368064 1286672 jdk.internal.loader.ClassLoaders$AppClassLoader
70 // ...
71
72 static Pattern clLine = Pattern.compile("0x\\p{XDigit}*\\s*0x\\p{XDigit}*\\s*0x\\p{XDigit}*\\s*(\\d*)\\s*(\\d*)\\s*(\\d*)\\s*(.*)");
73 static Pattern anonLine = Pattern.compile("\\s*(\\d*)\\s*(\\d*)\\s*(\\d*)\\s*.*");
74
75 public static DummyClassLoader dummyloader;
76
77 public void run(CommandExecutor executor) throws ClassNotFoundException {
78
79 // create a classloader and load our special classes
80 dummyloader = new DummyClassLoader();
81 Class<?> c = Class.forName("TestClass", true, dummyloader);
82 if (c.getClassLoader() != dummyloader) {
83 Assert.fail("TestClass defined by wrong classloader: " + c.getClassLoader());
84 }
85
86 OutputAnalyzer output = executor.execute("VM.classloader_stats");
87 Iterator<String> lines = output.asLines().iterator();
88 while (lines.hasNext()) {
89 String line = lines.next();
90 Matcher m = clLine.matcher(line);
91 if (m.matches()) {
92 // verify that DummyClassLoader has loaded 1 class, 1 anonymous class, and 1 hidden class
93 if (m.group(4).equals("ClassLoaderStatsTest$DummyClassLoader")) {
94 System.out.println("DummyClassLoader line: " + line);
95 if (!m.group(1).equals("1")) {
96 Assert.fail("Should have loaded 1 class: " + line);
97 }
98 checkPositiveInt(m.group(2));
99 checkPositiveInt(m.group(3));
100
101 String next = lines.next();
102 System.out.println("DummyClassLoader next: " + next);
103 if (!next.contains("unsafe anonymous classes")) {
104 Assert.fail("Should have an anonymous class");
105 }
106 Matcher m1 = anonLine.matcher(next);
107 m1.matches();
108 if (!m1.group(1).equals("1")) {
109 Assert.fail("Should have loaded 1 anonymous class, but found : " + m1.group(1));
110 }
111 checkPositiveInt(m1.group(2));
112 checkPositiveInt(m1.group(3));
113
114 next = lines.next();
115 System.out.println("DummyClassLoader next: " + next);
116 if (!next.contains("hidden classes")) {
117 Assert.fail("Should have a hidden class");
118 }
119 Matcher m2 = anonLine.matcher(next);
120 m2.matches();
121 if (!m2.group(1).equals("1")) {
122 Assert.fail("Should have loaded 1 hidden class, but found : " + m2.group(1));
123 }
124 checkPositiveInt(m2.group(2));
125 checkPositiveInt(m2.group(3));
126 }
127 }
128 }
129 }
130
131 private static void checkPositiveInt(String s) {
132 if (Integer.parseInt(s) <= 0) {
133 Assert.fail("Value should have been > 0: " + s);
134 }
135 }
136
137 public static class DummyClassLoader extends ClassLoader {
138
139 public static final String CLASS_NAME = "TestClass";
140
141 static ByteBuffer readClassFile(String name)
142 {
143 File f = new File(System.getProperty("test.classes", "."), name);
144 try (FileInputStream fin = new FileInputStream(f);
145 FileChannel fc = fin.getChannel())
146 {
147 return fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
148 } catch (IOException e) {
149 Assert.fail("Can't open file: " + name, e);
150 }
151
152 /* Will not reach here as Assert.fail() throws exception */
153 return null;
154 }
155
156 protected Class<?> loadClass(String name, boolean resolve)
157 throws ClassNotFoundException
158 {
159 Class<?> c;
160 if (!"TestClass".equals(name)) {
161 c = super.loadClass(name, resolve);
162 } else {
163 // should not delegate to the system class loader
168 }
169 return c;
170 }
171
172 protected Class<?> findClass(String name)
173 throws ClassNotFoundException
174 {
175 if (!"TestClass".equals(name)) {
176 throw new ClassNotFoundException("Unexpected class: " + name);
177 }
178 return defineClass(name, readClassFile(name + ".class"), null);
179 }
180 } /* DummyClassLoader */
181
182 @Test
183 public void jmx() throws ClassNotFoundException {
184 run(new JMXExecutor());
185 }
186 }
187
188 class HiddenClass { }
189
190 class TestClass {
191 private static final String HCName = "HiddenClass.class";
192 private static final String DIR = System.getProperty("test.classes");
193 static Unsafe unsafe = Unsafe.getUnsafe();
194
195 static {
196 try {
197 // Create a hidden weak class and an anonymous class.
198 byte[] klassBuf = readClassFile(DIR + File.separator + HCName);
199 Class<?> hc = defineHiddenClass(klassBuf);
200 Class ac = unsafe.defineAnonymousClass(TestClass.class, klassBuf, new Object[0]);
201 } catch (Throwable e) {
202 throw new RuntimeException("Unexpected exception in TestClass: " + e.getMessage());
203 }
204 }
205
206
207 static byte[] readClassFile(String classFileName) throws Exception {
208 File classFile = new File(classFileName);
209 try (FileInputStream in = new FileInputStream(classFile);
210 ByteArrayOutputStream out = new ByteArrayOutputStream())
211 {
212 int b;
213 while ((b = in.read()) != -1) {
214 out.write(b);
215 }
216 return out.toByteArray();
217 }
218 }
219
220 static Class<?> defineHiddenClass(byte[] bytes) throws Exception {
221 Lookup lookup = MethodHandles.lookup();
222 Class<?> hc = lookup.defineHiddenClass(bytes, false, NESTMATE).lookupClass();
223 return hc;
224 }
225 }
|