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