001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: *
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */
018:
019: /**
020: * @author Aleksander V. Budniy
021: * @version $Revision: $
022: */
023:
024: /**
025: * Created on 25.11.2006
026: */package org.apache.harmony.jpda.tests.jdwp.Events;
027:
028: import java.io.IOException;
029: import java.io.InputStream;
030: import java.net.URL;
031:
032: import org.apache.harmony.jpda.tests.framework.LogWriter;
033: import org.apache.harmony.jpda.tests.framework.TestErrorException;
034: import org.apache.harmony.jpda.tests.share.JPDADebuggeeSynchronizer;
035: import org.apache.harmony.jpda.tests.share.SyncDebuggee;
036:
037: /**
038: * Debuggee for ClassUnloadTest unit test.
039: */
040: public class ClassUnloadDebuggee extends SyncDebuggee {
041:
042: public static final String TESTED_CLASS_NAME = "org.apache.harmony.jpda.tests.jdwp.Events.ClassUnloadTestedClass";
043:
044: public static final int ARRAY_SIZE_FOR_MEMORY_STRESS = 1000000;
045:
046: public static volatile boolean classUnloaded = false;
047:
048: public static void main(String[] args) {
049: runDebuggee(ClassUnloadDebuggee.class);
050: }
051:
052: public void run() {
053: logWriter.println("--> ClassUnloadDebuggee started");
054:
055: // Test class prepare
056: logWriter.println("--> Load and prepare tested class");
057: CustomLoader loader = new CustomLoader(logWriter);
058:
059: Class cls = null;
060: try {
061: cls = Class.forName(TESTED_CLASS_NAME, true, loader);
062: logWriter.println("--> Tested class loaded: " + cls);
063: } catch (Exception e) {
064: logWriter.println("--> Unable to load tested class: " + e);
065: throw new TestErrorException(e);
066: }
067:
068: synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_READY);
069: synchronizer
070: .receiveMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
071:
072: logWriter
073: .println("--> Erase references to loaded class and its class loader");
074: classUnloaded = false;
075: cls = null;
076: loader = null;
077:
078: logWriter.println("--> Create memory stress and start gc");
079: createMemoryStress(1000000, ARRAY_SIZE_FOR_MEMORY_STRESS);
080: // createMemoryStress(100000000, 1024);
081: System.gc();
082:
083: String status = (classUnloaded ? "UNLOADED" : "LOADED");
084: logWriter.println("--> Class status after memory stress: "
085: + status);
086: synchronizer.sendMessage(status);
087: synchronizer
088: .receiveMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
089:
090: logWriter.println("--> ClassUnloadDebuggee finished");
091: }
092:
093: /*
094: * Stress algorithm for eating memory.
095: */
096: protected void createMemoryStress(int arrayLength_0,
097: int arrayLength_1) {
098: Runtime currentRuntime = Runtime.getRuntime();
099: long freeMemory = currentRuntime.freeMemory();
100: logWriter
101: .println("--> Debuggee: createMemoryStress: freeMemory (bytes) before memory stress = "
102: + freeMemory);
103:
104: long[][] longArrayForCreatingMemoryStress = null;
105:
106: int i = 0;
107: try {
108: longArrayForCreatingMemoryStress = new long[arrayLength_0][];
109: for (; i < longArrayForCreatingMemoryStress.length; i++) {
110: longArrayForCreatingMemoryStress[i] = new long[arrayLength_1];
111: }
112: logWriter
113: .println("--> Debuggee: createMemoryStress: NO OutOfMemoryError!!!");
114: } catch (OutOfMemoryError outOfMem) {
115: longArrayForCreatingMemoryStress = null;
116: logWriter
117: .println("--> Debuggee: createMemoryStress: OutOfMemoryError!!!");
118: }
119: freeMemory = currentRuntime.freeMemory();
120: logWriter
121: .println("--> Debuggee: createMemoryStress: freeMemory after creating memory stress = "
122: + freeMemory);
123:
124: longArrayForCreatingMemoryStress = null;
125: }
126:
127: /**
128: * More eager algorithm for eating memory.
129: */
130: /*
131: protected void createMemoryStress(int maxChunkSize, int minChunkSize) {
132: Runtime currentRuntime = Runtime.getRuntime();
133: long freeMemory = currentRuntime.freeMemory();
134: logWriter.println
135: ("--> Debuggee: createMemoryStress: freeMemory (bytes) before memory stress = " + freeMemory);
136:
137: LinkedList list = new LinkedList();
138: int countOOM = 0;
139:
140: for (int chunkSize = maxChunkSize; chunkSize >= minChunkSize; chunkSize /= 2) {
141: try {
142: for (;;) {
143: long[] chunk = new long[chunkSize];
144: list.add(chunk);
145: }
146: } catch (OutOfMemoryError outOfMem) {
147: countOOM++;
148: System.gc();
149: }
150: }
151:
152: // enable to collect allocated memory
153: list = null;
154:
155: freeMemory = currentRuntime.freeMemory();
156: logWriter.println
157: ("--> Debuggee: createMemoryStress: freeMemory after creating memory stress = " + freeMemory);
158:
159: logWriter.println
160: ("--> Debuggee: createMemoryStress: OutOfMemoryError occured: " + countOOM);
161: }
162: */
163:
164: /**
165: * Custom class loader to be used for tested class.
166: * It will be collected and finalized when tested class is unloaded.
167: */
168: static class CustomLoader extends ClassLoader {
169: private LogWriter logWriter;
170:
171: public CustomLoader(LogWriter writer) {
172: this .logWriter = writer;
173: }
174:
175: public Class<?> loadClass(String name)
176: throws ClassNotFoundException {
177: if (TESTED_CLASS_NAME.equals(name)) {
178: // load only tested class with this loader
179: return findClass(name);
180: }
181: return getParent().loadClass(name);
182: }
183:
184: public Class<?> findClass(String name)
185: throws ClassNotFoundException {
186: try {
187: logWriter
188: .println("-->> CustomClassLoader: Find class: "
189: + name);
190: String res = name.replace('.', '/') + ".class";
191: URL url = getResource(res);
192: logWriter
193: .println("-->> CustomClassLoader: Found class file: "
194: + res);
195: InputStream is = url.openStream();
196: int size = 1024;
197: byte bytes[] = new byte[size];
198: int len = loadClassData(is, bytes, size);
199: logWriter
200: .println("-->> CustomClassLoader: Loaded class bytes: "
201: + len);
202: Class cls = defineClass(name, bytes, 0, len);
203: logWriter
204: .println("-->> CustomClassLoader: Defined class: "
205: + cls);
206: // resolveClass(cls);
207: // logWriter.println("-->> CustomClassLoader: Resolved class: " + cls);
208: return cls;
209: } catch (Exception e) {
210: throw new ClassNotFoundException("Cannot load class: "
211: + name, e);
212: }
213: }
214:
215: private int loadClassData(InputStream in, byte[] raw, int size)
216: throws IOException {
217: int len = in.read(raw);
218: if (len >= size)
219: throw new IOException("Class file is too big: " + len);
220: in.close();
221: return len;
222: }
223:
224: protected void finalize() throws Throwable {
225: logWriter
226: .println("-->> CustomClassLoader: Class loader finalized => tested class UNLOADED");
227: ClassUnloadDebuggee.classUnloaded = true;
228: }
229: }
230: }
231:
232: /**
233: * Internal class used in ClassUnloadTest
234: */
235: class ClassUnloadTestedClass {
236: }
|