blob: 3a2ac9be332a14b7084988254d964906348166bb [file] [log] [blame]
Mathieu Chartier05aa4d32015-09-19 12:44:38 -07001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17import java.lang.ref.WeakReference;
18import java.lang.reflect.Constructor;
19import java.lang.reflect.Method;
20
21public class Main {
22 static final String DEX_FILE = System.getenv("DEX_LOCATION") + "/141-class-unload-ex.jar";
23
24 public static void main(String[] args) throws Exception {
25 Class pathClassLoader = Class.forName("dalvik.system.PathClassLoader");
26 if (pathClassLoader == null) {
27 throw new AssertionError("Couldn't find path class loader class");
28 }
29 Constructor constructor =
30 pathClassLoader.getDeclaredConstructor(String.class, ClassLoader.class);
31 try {
32 testUnloadClassAndLoader(constructor);
33 // Test that we don't unload if we have a Method keeping the class live.
34 testNoUnloadInvoke(constructor);
35 // Test that we don't unload if we have an instance.
36 testNoUnloadInstance(constructor);
37 // Stress test to make sure we dont leak memory.
38 stressTest(constructor);
39 } catch (Exception e) {
40 System.out.println(e);
41 }
42 }
43
44 private static void stressTest(Constructor constructor) throws Exception {
45 for (int i = 0; i <= 100; ++i) {
46 setUpUnloadLoader(constructor);
47 if (i % 10 == 0) {
48 Runtime.getRuntime().gc();
49 }
50 }
51 }
52
53 private static void testUnloadClassAndLoader(Constructor constructor) throws Exception {
54 WeakReference<ClassLoader> loader = setUpUnloadLoader(constructor);
55 WeakReference<Class> klass = setUpUnloadClass(constructor);
56 // No strong refernces to class loader, should get unloaded.
57 Runtime.getRuntime().gc();
58 WeakReference<Class> klass2 = setUpUnloadClass(constructor);
59 Runtime.getRuntime().gc();
60 // If the weak reference is cleared, then it was unloaded.
61 System.out.println(klass.get());
62 System.out.println(klass2.get());
63 System.out.println(loader.get());
64 }
65
66 private static void testNoUnloadInvoke(Constructor constructor) throws Exception {
67 WeakReference<ClassLoader> loader =
68 new WeakReference((ClassLoader) constructor.newInstance(
69 DEX_FILE, ClassLoader.getSystemClassLoader()));
70 WeakReference<Class> intHolder = new WeakReference(loader.get().loadClass("IntHolder"));
71 intHolder.get().getDeclaredMethod("runGC").invoke(intHolder.get());
72 boolean isNull = loader.get() == null;
73 System.out.println("loader null " + isNull);
74 }
75
76 private static void testNoUnloadInstance(Constructor constructor) throws Exception {
77 WeakReference<ClassLoader> loader =
78 new WeakReference((ClassLoader) constructor.newInstance(
79 DEX_FILE, ClassLoader.getSystemClassLoader()));
80 WeakReference<Class> intHolder = new WeakReference(loader.get().loadClass("IntHolder"));
81 Object o = intHolder.get().newInstance();
82 Runtime.getRuntime().gc();
83 boolean isNull = loader.get() == null;
84 System.out.println("loader null " + isNull);
85 }
86
87 private static WeakReference<Class> setUpUnloadClass(Constructor constructor)
88 throws Exception {
89 ClassLoader loader = (ClassLoader) constructor.newInstance(
90 DEX_FILE, ClassLoader.getSystemClassLoader());
91 Class intHolder = loader.loadClass("IntHolder");
92 Method getValue = intHolder.getDeclaredMethod("getValue");
93 Method setValue = intHolder.getDeclaredMethod("setValue", Integer.TYPE);
94 // Make sure we don't accidentally preserve the value in the int holder, the class
95 // initializer should be re-run.
96 System.out.println((int) getValue.invoke(intHolder));
97 setValue.invoke(intHolder, 2);
98 System.out.println((int) getValue.invoke(intHolder));
99 return new WeakReference(intHolder);
100 }
101
102 private static WeakReference<ClassLoader> setUpUnloadLoader(Constructor constructor)
103 throws Exception {
104 ClassLoader loader = (ClassLoader) constructor.newInstance(
105 DEX_FILE, ClassLoader.getSystemClassLoader());
106 Class intHolder = loader.loadClass("IntHolder");
107 Method setValue = intHolder.getDeclaredMethod("setValue", Integer.TYPE);
108 setValue.invoke(intHolder, 2);
109 return new WeakReference(loader);
110 }
111
112}