• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License.
17  */
18 
19 /**
20  * @author Aleksander V. Budniy
21  */
22 
23 /**
24  * Created on 25.11.2006
25  */
26 package org.apache.harmony.jpda.tests.jdwp.Events;
27 
28 import java.io.IOException;
29 import java.io.InputStream;
30 import java.net.URL;
31 
32 import org.apache.harmony.jpda.tests.framework.LogWriter;
33 import org.apache.harmony.jpda.tests.framework.TestErrorException;
34 import org.apache.harmony.jpda.tests.share.JPDADebuggeeSynchronizer;
35 import org.apache.harmony.jpda.tests.share.SyncDebuggee;
36 
37 /**
38  * Debuggee for ClassUnloadTest unit test.
39  */
40 public class ClassUnloadDebuggee extends SyncDebuggee {
41 
42 	public static final String TESTED_CLASS_NAME =
43 		"org.apache.harmony.jpda.tests.jdwp.Events.ClassUnloadTestedClass";
44 
45 	public static final int ARRAY_SIZE_FOR_MEMORY_STRESS = 1000000;
46 
47 	public static volatile boolean classUnloaded = false;
48 
main(String[] args)49 	public static void main(String[] args) {
50         runDebuggee(ClassUnloadDebuggee.class);
51     }
52 
53     @Override
run()54     public void run() {
55         logWriter.println("--> ClassUnloadDebuggee started");
56 
57         // Test class prepare
58         logWriter.println("--> Load and prepare tested class");
59         CustomLoader loader = new CustomLoader(logWriter);
60 
61         Class<?> cls = null;
62         try {
63 			cls = Class.forName(TESTED_CLASS_NAME, true, loader);
64 	        logWriter.println("--> Tested class loaded: " + cls);
65 		} catch (Exception e) {
66 	        logWriter.println("--> Unable to load tested class: " + e);
67 			throw new TestErrorException(e);
68 		}
69 
70         synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_READY);
71         synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
72 
73         logWriter.println("--> Erase references to loaded class and its class loader");
74         classUnloaded = false;
75         cls = null;
76         loader = null;
77 
78         logWriter.println("--> Create memory stress and start gc");
79         createMemoryStress(1000000, ARRAY_SIZE_FOR_MEMORY_STRESS);
80 //        createMemoryStress(100000000, 1024);
81         System.gc();
82 
83         String status = (classUnloaded ? "UNLOADED" : "LOADED");
84         logWriter.println("--> Class status after memory stress: " + status);
85         synchronizer.sendMessage(status);
86         synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
87 
88         logWriter.println("--> ClassUnloadDebuggee finished");
89     }
90 
91     /*
92      * Stress algorithm for eating memory.
93      */
createMemoryStress(int arrayLength_0, int arrayLength_1)94     protected void createMemoryStress(int arrayLength_0, int arrayLength_1) {
95         Runtime currentRuntime = Runtime.getRuntime();
96         long freeMemory = currentRuntime.freeMemory();
97         logWriter.println
98         ("--> Debuggee: createMemoryStress: freeMemory (bytes) before memory stress = " + freeMemory);
99 
100         long[][] longArrayForCreatingMemoryStress = null;
101 
102         int i = 0;
103         try {
104             longArrayForCreatingMemoryStress = new long[arrayLength_0][];
105             for (; i < longArrayForCreatingMemoryStress.length; i++) {
106                 longArrayForCreatingMemoryStress[i] = new long[arrayLength_1];
107             }
108             logWriter.println("--> Debuggee: createMemoryStress: NO OutOfMemoryError!!!");
109         } catch ( OutOfMemoryError outOfMem ) {
110             longArrayForCreatingMemoryStress = null;
111             logWriter.println("--> Debuggee: createMemoryStress: OutOfMemoryError!!!");
112         }
113         freeMemory = currentRuntime.freeMemory();
114         logWriter.println
115         ("--> Debuggee: createMemoryStress: freeMemory after creating memory stress = " + freeMemory);
116 
117         longArrayForCreatingMemoryStress = null;
118     }
119 
120     /**
121      * More eager algorithm for eating memory.
122      */
123 /*
124 	protected void createMemoryStress(int maxChunkSize, int minChunkSize) {
125         Runtime currentRuntime = Runtime.getRuntime();
126         long freeMemory = currentRuntime.freeMemory();
127         logWriter.println
128         ("--> Debuggee: createMemoryStress: freeMemory (bytes) before memory stress = " + freeMemory);
129 
130         LinkedList list = new LinkedList();
131         int countOOM = 0;
132 
133         for (int chunkSize = maxChunkSize; chunkSize >= minChunkSize; chunkSize /= 2) {
134         	try {
135                 for (;;) {
136                 	long[] chunk = new long[chunkSize];
137                 	list.add(chunk);
138                 }
139             } catch (OutOfMemoryError outOfMem) {
140                 countOOM++;
141                 System.gc();
142         	}
143         }
144 
145         // enable to collect allocated memory
146         list = null;
147 
148         freeMemory = currentRuntime.freeMemory();
149         logWriter.println
150         ("--> Debuggee: createMemoryStress: freeMemory after creating memory stress = " + freeMemory);
151 
152         logWriter.println
153         ("--> Debuggee: createMemoryStress: OutOfMemoryError occured: " + countOOM);
154     }
155 */
156 
157     /**
158      * Custom class loader to be used for tested class.
159      * It will be collected and finalized when tested class is unloaded.
160      */
161     static class CustomLoader extends ClassLoader {
162         private LogWriter logWriter;
163 
CustomLoader(LogWriter writer)164         public CustomLoader(LogWriter writer) {
165             this.logWriter = writer;
166         }
167 
168         @Override
loadClass(String name)169         public Class<?> loadClass(String name) throws ClassNotFoundException {
170             if (TESTED_CLASS_NAME.equals(name)) {
171                 // load only tested class with this loader
172                 return findClass(name);
173             }
174             return getParent().loadClass(name);
175         }
176 
177         @Override
findClass(String name)178         public Class<?> findClass(String name) throws ClassNotFoundException {
179             try {
180                 logWriter.println("-->> CustomClassLoader: Find class: " + name);
181 	        	String res = name.replace('.', '/') + ".class";
182 	            URL url = getResource(res);
183                 logWriter.println("-->> CustomClassLoader: Found class file: " + res);
184 	    		InputStream is = url.openStream();
185 	            int size = 1024;
186 	            byte bytes[] = new byte[size];
187 	            int len = loadClassData(is, bytes, size);
188                 logWriter.println("-->> CustomClassLoader: Loaded class bytes: " + len);
189 	            Class<?> cls = defineClass(name, bytes, 0, len);
190                 logWriter.println("-->> CustomClassLoader: Defined class: " + cls);
191 //	            resolveClass(cls);
192 //                logWriter.println("-->> CustomClassLoader: Resolved class: " + cls);
193 	            return cls;
194         	} catch (Exception e) {
195         		throw new ClassNotFoundException("Cannot load class: " + name, e);
196         	}
197         }
198 
loadClassData(InputStream in, byte[] raw, int size)199         private int loadClassData(InputStream in, byte[] raw, int size) throws IOException {
200             int len = in.read(raw);
201             if (len >= size)
202                 throw new IOException("Class file is too big: " + len);
203             in.close();
204             return len;
205         }
206 
207         @Override
finalize()208         protected void finalize() throws Throwable {
209             logWriter.println("-->> CustomClassLoader: Class loader finalized => tested class UNLOADED");
210             ClassUnloadDebuggee.classUnloaded = true;
211        }
212     }
213 }
214 
215 /**
216  * Internal class used in ClassUnloadTest
217  */
218 class ClassUnloadTestedClass {
219 }
220