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 49 public static void main(String[] args) { 50 runDebuggee(ClassUnloadDebuggee.class); 51 } 52 53 public void run() { 54 logWriter.println("--> ClassUnloadDebuggee started"); 55 56 // Test class prepare 57 logWriter.println("--> Load and prepare tested class"); 58 CustomLoader loader = new CustomLoader(logWriter); 59 60 Class cls = null; 61 try { 62 cls = Class.forName(TESTED_CLASS_NAME, true, loader); 63 logWriter.println("--> Tested class loaded: " + cls); 64 } catch (Exception e) { 65 logWriter.println("--> Unable to load tested class: " + e); 66 throw new TestErrorException(e); 67 } 68 69 synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_READY); 70 synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE); 71 72 logWriter.println("--> Erase references to loaded class and its class loader"); 73 classUnloaded = false; 74 cls = null; 75 loader = null; 76 77 logWriter.println("--> Create memory stress and start gc"); 78 createMemoryStress(1000000, ARRAY_SIZE_FOR_MEMORY_STRESS); 79 // createMemoryStress(100000000, 1024); 80 System.gc(); 81 82 String status = (classUnloaded ? "UNLOADED" : "LOADED"); 83 logWriter.println("--> Class status after memory stress: " + status); 84 synchronizer.sendMessage(status); 85 synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE); 86 87 logWriter.println("--> ClassUnloadDebuggee finished"); 88 } 89 90 /* 91 * Stress algorithm for eating memory. 92 */ 93 protected void createMemoryStress(int arrayLength_0, int arrayLength_1) { 94 Runtime currentRuntime = Runtime.getRuntime(); 95 long freeMemory = currentRuntime.freeMemory(); 96 logWriter.println 97 ("--> Debuggee: createMemoryStress: freeMemory (bytes) before memory stress = " + freeMemory); 98 99 long[][] longArrayForCreatingMemoryStress = null; 100 101 int i = 0; 102 try { 103 longArrayForCreatingMemoryStress = new long[arrayLength_0][]; 104 for (; i < longArrayForCreatingMemoryStress.length; i++) { 105 longArrayForCreatingMemoryStress[i] = new long[arrayLength_1]; 106 } 107 logWriter.println("--> Debuggee: createMemoryStress: NO OutOfMemoryError!!!"); 108 } catch ( OutOfMemoryError outOfMem ) { 109 longArrayForCreatingMemoryStress = null; 110 logWriter.println("--> Debuggee: createMemoryStress: OutOfMemoryError!!!"); 111 } 112 freeMemory = currentRuntime.freeMemory(); 113 logWriter.println 114 ("--> Debuggee: createMemoryStress: freeMemory after creating memory stress = " + freeMemory); 115 116 longArrayForCreatingMemoryStress = null; 117 } 118 119 /** 120 * More eager algorithm for eating memory. 121 */ 122 /* 123 protected void createMemoryStress(int maxChunkSize, int minChunkSize) { 124 Runtime currentRuntime = Runtime.getRuntime(); 125 long freeMemory = currentRuntime.freeMemory(); 126 logWriter.println 127 ("--> Debuggee: createMemoryStress: freeMemory (bytes) before memory stress = " + freeMemory); 128 129 LinkedList list = new LinkedList(); 130 int countOOM = 0; 131 132 for (int chunkSize = maxChunkSize; chunkSize >= minChunkSize; chunkSize /= 2) { 133 try { 134 for (;;) { 135 long[] chunk = new long[chunkSize]; 136 list.add(chunk); 137 } 138 } catch (OutOfMemoryError outOfMem) { 139 countOOM++; 140 System.gc(); 141 } 142 } 143 144 // enable to collect allocated memory 145 list = null; 146 147 freeMemory = currentRuntime.freeMemory(); 148 logWriter.println 149 ("--> Debuggee: createMemoryStress: freeMemory after creating memory stress = " + freeMemory); 150 151 logWriter.println 152 ("--> Debuggee: createMemoryStress: OutOfMemoryError occured: " + countOOM); 153 } 154 */ 155 156 /** 157 * Custom class loader to be used for tested class. 158 * It will be collected and finalized when tested class is unloaded. 159 */ 160 static class CustomLoader extends ClassLoader { 161 private LogWriter logWriter; 162 163 public CustomLoader(LogWriter writer) { 164 this.logWriter = writer; 165 } 166 167 public Class<?> loadClass(String name) throws ClassNotFoundException { 168 if (TESTED_CLASS_NAME.equals(name)) { 169 // load only tested class with this loader 170 return findClass(name); 171 } 172 return getParent().loadClass(name); 173 } 174 175 public Class<?> findClass(String name) throws ClassNotFoundException { 176 try { 177 logWriter.println("-->> CustomClassLoader: Find class: " + name); 178 String res = name.replace('.', '/') + ".class"; 179 URL url = getResource(res); 180 logWriter.println("-->> CustomClassLoader: Found class file: " + res); 181 InputStream is = url.openStream(); 182 int size = 1024; 183 byte bytes[] = new byte[size]; 184 int len = loadClassData(is, bytes, size); 185 logWriter.println("-->> CustomClassLoader: Loaded class bytes: " + len); 186 Class cls = defineClass(name, bytes, 0, len); 187 logWriter.println("-->> CustomClassLoader: Defined class: " + cls); 188 // resolveClass(cls); 189 // logWriter.println("-->> CustomClassLoader: Resolved class: " + cls); 190 return cls; 191 } catch (Exception e) { 192 throw new ClassNotFoundException("Cannot load class: " + name, e); 193 } 194 } 195 196 private int loadClassData(InputStream in, byte[] raw, int size) throws IOException { 197 int len = in.read(raw); 198 if (len >= size) 199 throw new IOException("Class file is too big: " + len); 200 in.close(); 201 return len; 202 } 203 204 protected void finalize() throws Throwable { 205 logWriter.println("-->> CustomClassLoader: Class loader finalized => tested class UNLOADED"); 206 ClassUnloadDebuggee.classUnloaded = true; 207 } 208 } 209 } 210 211 /** 212 * Internal class used in ClassUnloadTest 213 */ 214 class ClassUnloadTestedClass { 215 } 216