001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.test.classloader.leak.clstore;
023:
024: import java.io.ByteArrayInputStream;
025: import java.io.ByteArrayOutputStream;
026: import java.io.File;
027: import java.io.FileOutputStream;
028: import java.io.ObjectInputStream;
029: import java.io.ObjectOutputStream;
030: import java.io.PrintStream;
031: import java.io.Serializable;
032: import java.lang.ref.WeakReference;
033: import java.util.HashMap;
034: import java.util.Map;
035:
036: import org.jboss.logging.Logger;
037:
038: public class ClassLoaderStore {
039: private static final Logger log = Logger
040: .getLogger(ClassLoaderStore.class);
041:
042: private static ClassLoaderStore instance = new ClassLoaderStore();
043:
044: private final Map classloaders = new HashMap();
045:
046: private ClassLoaderStore() {
047:
048: }
049:
050: public static ClassLoaderStore getInstance() {
051: return instance;
052: }
053:
054: public void storeClassLoader(String key, ClassLoader loader) {
055: log.debug("Storing " + loader + " under " + key);
056: ClassLoader parent = loader.getParent();
057: while (parent != null) {
058: log.debug("Parent is " + parent);
059: parent = parent.getParent();
060: }
061: WeakReference ref = new WeakReference(loader);
062: classloaders.put(key, ref);
063: }
064:
065: public ClassLoader getClassLoader(String key, boolean forceGC,
066: String reportFile) {
067: ClassLoader result = null;
068: WeakReference ref = (WeakReference) classloaders.get(key);
069: if (ref != null) {
070: result = (ClassLoader) ref.get();
071: if (result != null && forceGC) {
072: try {
073: result = null; // Don't hold a ref to it here while analyzing heap
074: result = getClassLoader(ref, reportFile);
075: } catch (Exception e) {
076: log
077: .error(
078: "Caught exception checking for classloader release",
079: e);
080: }
081: }
082: }
083:
084: return result;
085: }
086:
087: /**
088: * If you started your class with -agentlib:jbossAgent in case of leakage (if className still loaded) a file (reportFile) will be created, and a heapSnapshot(./snapshot,mem)
089: *
090: * @param weakReferenceOnLoader A weakReference to the created ClassLoader. If there is no references to this classLoader this reference will be cleared
091: * @param className The class name supposed to be unloade.
092: * @param reportHTMLFile the report file
093: * @throws Exception
094: */
095: private ClassLoader getClassLoader(
096: WeakReference weakReferenceOnLoader, String reportHTMLFile)
097: throws Exception {
098: LeakAnalyzer leakAnalyzer = null;
099: try {
100: leakAnalyzer = new LeakAnalyzer();
101: } catch (Throwable t) {
102: log.debug("Could not instantiate JVMTIInterface:"
103: + t.getLocalizedMessage());
104: }
105:
106: if (leakAnalyzer != null && leakAnalyzer.isActive()) {
107: leakAnalyzer.forceGC();
108:
109: if (weakReferenceOnLoader.get() == null) {
110: return null;
111: }
112:
113: fillMemory(weakReferenceOnLoader);
114:
115: if (weakReferenceOnLoader.get() == null) {
116: return null;
117: }
118:
119: leakAnalyzer.heapSnapshot("snapshot", "mem");
120:
121: if (weakReferenceOnLoader.get() == null) {
122: return null;
123: }
124:
125: HashMap datapoints = leakAnalyzer.createIndexMatrix();
126:
127: if (weakReferenceOnLoader.get() == null) {
128: return null;
129: }
130:
131: String report = leakAnalyzer.exploreObjectReferences(
132: datapoints, weakReferenceOnLoader.get(), 18, true,
133: false);
134: log.info(report);
135: if (reportHTMLFile != null) {
136: File outputfile = new File(reportHTMLFile);
137: FileOutputStream outfile = new FileOutputStream(
138: outputfile);
139: PrintStream realoutput = new PrintStream(outfile);
140: realoutput.println(report);
141: realoutput.close();
142: }
143:
144: leakAnalyzer.forceGC();
145: } else {
146: log.debug("JVMTI not active; using System.gc()");
147: System.gc();
148: Thread.sleep(1000);
149:
150: if (weakReferenceOnLoader.get() != null)
151: fillMemory(weakReferenceOnLoader);
152:
153: if (weakReferenceOnLoader.get() != null)
154: fillMemory(weakReferenceOnLoader);
155: }
156:
157: return (ClassLoader) weakReferenceOnLoader.get();
158: }
159:
160: private void fillMemory(WeakReference ref) {
161: Runtime rt = Runtime.getRuntime();
162: int[] adds = { 0, 10, 20, 30, 40, 41, 42, 43, 44, 45, 46, 47,
163: 48, 49 };
164: for (int i = 0; i < adds.length; i++) {
165: int toAdd = adds[i];
166: System.gc();
167:
168: if (ref.get() == null)
169: break;
170:
171: // create garbage, filling a larger and larger % of
172: // free memory on each loop
173: long avail = rt.freeMemory();
174: int create = (int) (avail / 1000 * (950 + toAdd));
175: String pct = (95 + (toAdd / 10)) + "."
176: + (toAdd - ((toAdd / 10) * 10));
177: int bucket = create / 1000;
178: log.info("Filling " + pct
179: + "% of free memory. Free memory=" + avail
180: + " Total Memory=" + rt.totalMemory()
181: + " Max Memory=" + rt.maxMemory());
182:
183: try {
184: byte[][] bytez = new byte[1000][];
185: for (int j = 0; j < bytez.length; j++)
186: bytez[j] = new byte[bucket];
187: } catch (Throwable t) {
188: System.gc();
189: break;
190: }
191: }
192:
193: try {
194: ByteArrayOutputStream byteout = new ByteArrayOutputStream();
195: ObjectOutputStream out = new ObjectOutputStream(byteout);
196:
197: out.writeObject(new Dummy());
198:
199: ByteArrayInputStream byteInput = new ByteArrayInputStream(
200: byteout.toByteArray());
201: ObjectInputStream input = new ObjectInputStream(byteInput);
202: input.readObject();
203:
204: } catch (Exception e) {
205: e.printStackTrace();
206: }
207:
208: if (ref.get() != null)
209: System.gc();
210: }
211:
212: public void removeClassLoader(String key) {
213: classloaders.remove(key);
214: }
215:
216: /** Used just to serialize anything and release SoftCache on java Serialization */
217: private static class Dummy implements Serializable {
218: private static final long serialVersionUID = 1L;
219: }
220: }
|