Revision: 2780
          http://vexi.svn.sourceforge.net/vexi/?rev=2780&view=rev
Author:   mkpg2
Date:     2008-01-31 10:26:49 -0800 (Thu, 31 Jan 2008)

Log Message:
-----------
Feature. Memory leak hunting
   - dump the stack traces of created objects in descending order of their 
frequencies
   - show the reference chain from a static root to the leak

Modified Paths:
--------------
    trunk/core/org.vexi.devl/.classpath
    trunk/core/org.vexi.devl/.settings/org.eclipse.jdt.core.prefs
    trunk/core/org.vexi.devl/src/org/vexi/devl/Main.java

Added Paths:
-----------
    trunk/core/org.vexi.devl/lib/insanelib.jar
    trunk/core/org.vexi.devl/src/org/vexi/devl/Devl.java
    trunk/core/org.vexi.devl/src/org/vexi/devl/GCUtil.java

Removed Paths:
-------------
    trunk/core/org.vexi.devl/.settings/org.eclipse.jdt.ui.prefs

Property Changed:
----------------
    trunk/core/org.vexi.devl/


Property changes on: trunk/core/org.vexi.devl
___________________________________________________________________
Name: svn:ignore
   - src_gen

_vexi_test

_temp_

   + src_gen

_vexi_test

_temp_

bin


Modified: trunk/core/org.vexi.devl/.classpath
===================================================================
--- trunk/core/org.vexi.devl/.classpath 2008-01-31 18:18:33 UTC (rev 2779)
+++ trunk/core/org.vexi.devl/.classpath 2008-01-31 18:26:49 UTC (rev 2780)
@@ -1,13 +1,14 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
-       <classpathentry kind="src" path="src"/>
-       <classpathentry kind="src" path="src_gen"/>
-       <classpathentry 
excluding="testold/debug/|testold/debug/simple/|testold/debug/thread/|testold/debug/vars/"
 kind="src" path="src_junit"/>
-       <classpathentry combineaccessrules="false" kind="src" 
path="/org.ibex.js"/>
-       <classpathentry kind="con" 
path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
-       <classpathentry kind="lib" path="lib/commons-codec-1.3.jar"/>
-       <classpathentry kind="lib" path="lib/xmlrpc-2.0.jar"/>
-       <classpathentry kind="con" 
path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3.8.1"/>
-       <classpathentry combineaccessrules="false" kind="src" 
path="/org.vexi.core"/>
-       <classpathentry kind="output" path="bin"/>
-</classpath>
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="src" path="src"/>
+       <classpathentry kind="src" path="src_gen"/>
+       <classpathentry 
excluding="testold/debug/|testold/debug/simple/|testold/debug/thread/|testold/debug/vars/"
 kind="src" path="src_junit"/>
+       <classpathentry combineaccessrules="false" kind="src" 
path="/org.ibex.js"/>
+       <classpathentry kind="con" 
path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+       <classpathentry kind="lib" path="lib/commons-codec-1.3.jar"/>
+       <classpathentry kind="lib" path="lib/xmlrpc-2.0.jar"/>
+       <classpathentry kind="lib" path="lib/insanelib.jar"/>
+       <classpathentry kind="con" 
path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3.8.1"/>
+       <classpathentry combineaccessrules="false" kind="src" 
path="/org.vexi.core"/>
+       <classpathentry kind="output" path="bin"/>
+</classpath>

Modified: trunk/core/org.vexi.devl/.settings/org.eclipse.jdt.core.prefs
===================================================================
--- trunk/core/org.vexi.devl/.settings/org.eclipse.jdt.core.prefs       
2008-01-31 18:18:33 UTC (rev 2779)
+++ trunk/core/org.vexi.devl/.settings/org.eclipse.jdt.core.prefs       
2008-01-31 18:26:49 UTC (rev 2780)
@@ -1,12 +1,12 @@
-#Sat Sep 09 17:32:01 CEST 2006
-eclipse.preferences.version=1
-org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.2
-org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.4
-org.eclipse.jdt.core.compiler.debug.lineNumber=generate
-org.eclipse.jdt.core.compiler.debug.localVariable=generate
-org.eclipse.jdt.core.compiler.debug.sourceFile=generate
-org.eclipse.jdt.core.compiler.problem.assertIdentifier=warning
-org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning
-org.eclipse.jdt.core.compiler.source=1.3
+#Thu Jan 31 16:20:34 GMT 2008
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.4
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.4
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning
+org.eclipse.jdt.core.compiler.source=1.4

Deleted: trunk/core/org.vexi.devl/.settings/org.eclipse.jdt.ui.prefs
===================================================================
--- trunk/core/org.vexi.devl/.settings/org.eclipse.jdt.ui.prefs 2008-01-31 
18:18:33 UTC (rev 2779)
+++ trunk/core/org.vexi.devl/.settings/org.eclipse.jdt.ui.prefs 2008-01-31 
18:26:49 UTC (rev 2780)
@@ -1,3 +0,0 @@
-#Sat Sep 09 17:32:01 CEST 2006
-eclipse.preferences.version=1
-internal.default.compliance=default

Added: trunk/core/org.vexi.devl/lib/insanelib.jar
===================================================================
(Binary files differ)


Property changes on: trunk/core/org.vexi.devl/lib/insanelib.jar
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/core/org.vexi.devl/src/org/vexi/devl/Devl.java
===================================================================
--- trunk/core/org.vexi.devl/src/org/vexi/devl/Devl.java                        
        (rev 0)
+++ trunk/core/org.vexi.devl/src/org/vexi/devl/Devl.java        2008-01-31 
18:26:49 UTC (rev 2780)
@@ -0,0 +1,153 @@
+package org.vexi.devl;
+
+import java.awt.event.KeyEvent;
+import java.lang.ref.WeakReference;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import org.ibex.js.JS;
+import org.ibex.js.JSExn;
+import org.ibex.js.JSU;
+import org.ibex.util.Basket;
+import org.ibex.util.Log;
+import org.vexi.plat.Platform.Scheduler;
+
+public class Devl extends JS.Immutable implements JSU.Devl {
+       
+       static JS MARKER = new JS.Obj();
+       static WeakReference MARKER_REF;
+       
+       public JS get(JS key_) throws JSExn {
+               String key = JSU.toString(key_);
+               if("MARKER".equals(key)){
+                       if(MARKER == null) 
+                               return null;
+                       JS r = MARKER;
+                       MARKER_REF = new WeakReference(MARKER);
+                       MARKER = null;
+                       return r;
+               }
+               return null;
+       }
+       
+       public void interceptKeyPress(KeyEvent k){
+       if(k.getKeyCode() == KeyEvent.VK_F12)
+               dumpStacks();
+       else if(k.getKeyCode() == KeyEvent.VK_F11){
+               if(MARKER != null) Log.warn(Devl.class, "Marker has not been 
set yet");
+               else{
+                       GCUtil.assertGC("MARKER not collected", MARKER_REF);
+                       
+               }
+       }
+       }
+
+       
+       static private Integer ZERO = new Integer(0);
+       public void dumpStacks(){
+
+               System.err.println("Object creation dump");
+               
+               //while(JSU.stackToCount.size()>0){
+               for(int i=0;i<10 && stackToCount.size()>0; i++){
+                       Integer highest = ZERO; 
+                       Iterator Vs = stackToCount.values().iterator();
+                       while(Vs.hasNext()){
+                               Integer next = (Integer)Vs.next();
+                               if(next.intValue()>highest.intValue())
+                                       highest = next;
+                       }
+                       
+                       Iterator Ks = stackToCount.keySet().iterator();
+                       while(Ks.hasNext()){
+                               String k = (String)Ks.next();
+                               Integer v = (Integer)stackToCount.get(k);
+                               if(v.intValue()==highest.intValue()){
+                                       System.err.println(v);
+                                       System.err.println(k);
+                                       stackToCount.remove(k);
+                                       break;
+                               }
+                       }
+                       
+                       
+               }
+               
+       }
+       
+    
+    ////////
+    // MEMORY LEAK TRACKING
+    /////
+    // FEATURE - make this an option in the devl version that can be switched 
on
+       static private Map hashToObjInfo = new HashMap();
+    static private Map stackToCount = new HashMap();
+    
+       
+       static class ObjInfo{
+               final String bt; // the backtrace when it is created
+               ObjInfo(String bt){ this.bt = bt; }
+               String firstLine(){ return bt.split("\\n")[0]; }
+       }
+
+    static private boolean doesOverrideHashCode(Object o){
+               try {
+                       java.lang.reflect.Method m = 
o.getClass().getMethod("hashCode", new Class[]{});
+                       Class declaring = m.getDeclaringClass();
+                       if(Object.class!=declaring)
+                               return false;
+                       return true;
+               } catch (Exception e) {
+                       throw new RuntimeException(e);
+               }
+    }
+    
+       static public ObjInfo get(Object o){
+               if(!doesOverrideHashCode(o))
+                       return null;
+                       
+               Integer hash = new Integer(o.hashCode());
+           return (ObjInfo) hashToObjInfo.get(hash);
+       }
+    
+       public void register(Object o){
+               if(!(o instanceof JSExn.ExnJSObj)){
+                       if(!doesOverrideHashCode(o))
+                               throw new RuntimeException("Cannot register 
objects with overridden hashcodes " + o.getClass().getName());
+
+                       Integer hash = new Integer(o.hashCode());
+                       ObjInfo oi = objInfo();
+               hashToObjInfo.put(hash, oi);
+               
+               Integer c = (Integer)stackToCount.get(oi.bt);
+                       if(c==null) stackToCount.put(oi.bt,new Integer(0));
+                       else stackToCount.put(oi.bt,new 
Integer(c.intValue()+1));
+               }
+       }
+               
+       public void unregister(Object o){
+               if(!(o instanceof JSExn.ExnJSObj)){
+                       Integer hash = new Integer(o.hashCode());
+                       ObjInfo oi = (ObjInfo) hashToObjInfo.remove(hash);
+
+                       Integer c = (Integer)stackToCount.get(oi.bt);
+                       if(c.intValue()==1) stackToCount.remove(oi.bt);
+                       else stackToCount.put(oi.bt,new 
Integer(c.intValue()-1));
+               }
+       }
+    
+    
+    static public ObjInfo objInfo(){
+       Basket.List bt = JSU.backtrace();
+       StringBuffer b = new StringBuffer(512);
+       for(int i=0; i<bt.size(); i++){
+               if(i!=0) b.append("\n");
+               b.append(bt.get(i));
+       }
+       return new ObjInfo(b.toString().intern());
+    }
+    
+}


Property changes on: trunk/core/org.vexi.devl/src/org/vexi/devl/Devl.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Added: trunk/core/org.vexi.devl/src/org/vexi/devl/GCUtil.java
===================================================================
--- trunk/core/org.vexi.devl/src/org/vexi/devl/GCUtil.java                      
        (rev 0)
+++ trunk/core/org.vexi.devl/src/org/vexi/devl/GCUtil.java      2008-01-31 
18:26:49 UTC (rev 2780)
@@ -0,0 +1,238 @@
+/*
+ *                 Sun Public License Notice
+ * 
+ * The contents of this file are subject to the Sun Public License
+ * Version 1.0 (the "License"). You may not use this file except in
+ * compliance with the License. A copy of the License is available at
+ * http://www.sun.com/
+ * 
+ * The Original Code is NetBeans. The Initial Developer of the Original
+ * Code is Sun Microsystems, Inc. Portions Copyright 1997-2005 Sun
+ * Microsystems, Inc. All Rights Reserved.
+ */
+// Code derived from  NbTestCase
+
+
+package org.vexi.devl;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Set;
+
+import org.ibex.js.JS;
+import org.ibex.js.JSExn;
+import org.ibex.js.JSU;
+import org.ibex.util.Log;
+import org.netbeans.insane.scanner.ObjectMap;
+import org.netbeans.insane.scanner.ScannerUtils;
+import org.netbeans.insane.scanner.Visitor;
+/**
+ * 
+ */
+public abstract class GCUtil {
+    
+    
+    /** Assert GC. Tries to GC ref's referent.
+     * @param text the text to show when test fails.
+     * @param ref the referent to object that
+     * should be GCed
+     */
+    public static void assertGC(String text, java.lang.ref.Reference ref) {
+        ArrayList alloc = new ArrayList ();
+        int size = 100000;
+        for (int i = 0; i < 50; i++) {
+            if (ref.get() == null) {
+                return;
+            }
+            System.gc();
+            System.runFinalization();
+            try {
+                alloc.add (new byte[size]);
+                size = (int)(((double)size) * 1.3);
+            } catch (OutOfMemoryError error) {
+                size = size / 2;
+            }
+            try {
+                if (i % 3 == 0) Thread.sleep(321);
+            } catch (InterruptedException t) {
+                // ignore
+            }
+        }
+        alloc = null;
+        Log.uWarn("GCUtil", "Reference not GC'd. Processing heap now, this may 
take a while ..."); 
+        throw new AssertionError(text + ":\n" + findRefsFromRoot(ref.get()));
+    }
+
+    private static String findRefsFromRoot(final Object target) {
+        final Map objects = new IdentityHashMap();
+        boolean found = false;
+
+        Visitor vis = new Visitor() {
+            public void visitClass(Class cls) {}
+
+            public void visitObject(ObjectMap map, Object object) {
+                objects.put(object, new Entry(object));
+            }
+
+            public void visitArrayReference(ObjectMap map, Object from, Object 
to, int index) {
+                visitRef(from, to);
+            }
+
+            public void visitObjectReference(ObjectMap map, Object from, 
Object to, java.lang.reflect.Field ref) {
+                visitRef(from, to);
+            }
+        
+            private void visitRef(Object from, Object to) {
+                ((Entry)objects.get(from)).addOut(to);
+                ((Entry)objects.get(to)).addIn(from);
+                if (to == target) throw new RuntimeException("Done");
+            }
+
+
+            public void visitStaticReference(ObjectMap map, Object to, 
java.lang.reflect.Field ref) {
+                ((Entry)objects.get(to)).addStatic(ref);
+                if (to == target) throw new RuntimeException("Done");
+            }
+        };
+        
+        try {
+            
ScannerUtils.scanExclusivelyInAWT(ScannerUtils.skipNonStrongReferencesFilter(), 
vis, ScannerUtils.interestingRoots());
+        } catch (Exception ex) {
+            // found object
+            found = true;
+        }
+        
+        if (found) {
+            return findRoots(objects, target);
+        } else {
+            return "Not found!!!";
+        }
+    }
+        /** BFS scan of incomming refs*/
+    private static String  findRoots(Map objects, Object obj) {
+        class PathElement {
+            private Entry item;
+            private PathElement next; 
+            public PathElement(Entry item, PathElement next) {
+                this.item = item;
+                this.next = next;
+            }
+            
+            public Entry getItem() {
+                return item;
+            }
+            public String toString() {
+                if (next == null) {
+                    return item.toString();
+                } else {
+                    return item.toString() + "->\n" + next.toString();
+                }
+            }
+        }
+
+        Set visited = new HashSet();
+        Entry fin = (Entry)objects.get(obj);
+        assert(fin!=null);
+        
+        visited.add(fin);
+        LinkedList queue = new LinkedList();
+        queue.add(new PathElement(fin, null));
+        
+        while (!queue.isEmpty()) {
+            PathElement act = (PathElement)queue.remove(0);
+            // any static ref?
+            Iterator it = act.getItem().staticRefs();
+            if (it.hasNext()) {
+                Field fld = (Field)it.next();
+                return fld + "->\n" + act;
+            }
+            
+            // follow incomming
+            it = act.getItem().incommingRefs();
+            while(it.hasNext()) {
+                Entry ref = (Entry)objects.get(it.next());
+                assert(ref!=null);
+                
+                // add to the queue if not new
+                if (visited.add(ref)) queue.add(new PathElement(ref, act));
+            }
+        }
+        return "Error";
+    }
+    
+
+    static Object[] EMPTY = new Object[0];
+    
+    /** Entry represents one object and its incomming/outgoing refs */
+    private static class Entry {
+        private Object obj;
+        private Object[] in;
+        private Object[] out;
+        private Object[] stat;
+        
+        public Entry(Object o) {
+            obj = o;
+            in = EMPTY;
+            out = EMPTY;
+            stat = EMPTY;
+        }
+        
+        void addOut(Object o) {
+            out = append(out, o);
+        }
+        
+        void addStatic(Field ref) {
+            stat = append(stat, ref);
+        }
+        
+        void addIn(Object o) {
+            in = append(in, o);
+        }
+        
+        public Iterator incommingRefs() {
+            return Arrays.asList(in).iterator();
+        }
+
+        public Iterator staticRefs() {
+            return Arrays.asList(stat).iterator();
+        }
+
+        public Iterator outgoingRefs() {
+            return Arrays.asList(stat).iterator();
+        }
+        
+        private Object[] append(Object[] orig, Object add) {
+            int origLen = orig.length;
+            Object[] ret = new Object[origLen + 1];
+            System.arraycopy(orig, 0, ret, 0, origLen);
+            ret[origLen] = add;
+            return ret;
+        }
+        
+        public String toString() {
+               String r = "";
+               if(Devl.get(obj)!=null)
+                       r+= Devl.get(obj).firstLine() + ":";
+               else
+                       r+= "    ";
+               
+               if(obj instanceof JS){
+                       try {
+                                       return 
r+=JSU.json_marshal((JS)obj).coerceToString();
+                               } catch (JSExn e) {
+                                       return r+=obj.toString() + " (Could not 
stringify: "+e.getMessage()+")";
+                               }
+               }else{
+                       r+=obj.toString();
+               }
+            return r;
+               //return obj.getClass().getName() + "@" + 
Integer.toHexString(System.identityHashCode(obj));
+        }
+    }
+}


Property changes on: trunk/core/org.vexi.devl/src/org/vexi/devl/GCUtil.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Modified: trunk/core/org.vexi.devl/src/org/vexi/devl/Main.java
===================================================================
--- trunk/core/org.vexi.devl/src/org/vexi/devl/Main.java        2008-01-31 
18:18:33 UTC (rev 2779)
+++ trunk/core/org.vexi.devl/src/org/vexi/devl/Main.java        2008-01-31 
18:26:49 UTC (rev 2780)
@@ -5,6 +5,9 @@
 
 import org.ibex.js.DebugHandler;
 import org.ibex.js.Fountain;
+import org.ibex.js.JS;
+import org.ibex.js.JSExn;
+import org.ibex.js.JSU;
 import org.ibex.js.Scheduler;
 import org.ibex.util.Log;
 import org.vexi.core.DevlTemplateBuilder;
@@ -78,6 +81,8 @@
         
                Fountain rr = org.vexi.core.Main.init(args);
            
+               JSU.devl = new Devl();  
+               
            if(debugmode)
                DebugHandler.instance.init(rr);
         


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Vexi-svn mailing list
Vexi-svn@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/vexi-svn

Reply via email to