Back to index

lightning-sunbird  0.9+nobinonly
Classes | Static Public Member Functions | Static Package Functions | Static Private Attributes
leaksoup Class Reference

List of all members.

Classes

class  ByTypeBinSize
 Sorts the bins of a histogram by (count * typeSize) to show the most pressing leaks. More...

Static Public Member Functions

static void main (String[] args)

Static Package Functions

static void cook (String inputName)
static void printLeakHistogram (PrintWriter out, Histogram hist) throws IOException
static void printLeakStructure (PrintWriter out, Leak[] leaks)
static StringBuffer appendChar (StringBuffer buffer, int ch)
static void printField (PrintWriter out, Object field)
static void printLeaks (RandomAccessFile in, PrintWriter out, Leak[] leaks) throws IOException

Static Private Attributes

static boolean ROOTS_ONLY = false

Detailed Description

Definition at line 241 of file leaksoup.java.


Member Function Documentation

static StringBuffer leaksoup.appendChar ( StringBuffer  buffer,
int  ch 
) [inline, static, package]

Definition at line 539 of file leaksoup.java.

                                                                   {
              if (ch > 32 && ch < 0x7F) {
                     switch (ch) {
                     case '<':     buffer.append("&LT;"); break;
                     case '>':     buffer.append("&GT;"); break;
                     default:      buffer.append((char)ch); break;
                     }
              } else {
                     buffer.append("&#183;");
              }
              return buffer;
       }

Here is the caller graph for this function:

static void leaksoup.cook ( String  inputName) [inline, static, package]

Definition at line 277 of file leaksoup.java.

                                          {
              try {
                     Vector vec = new Vector();
                     Hashtable leakTable = new Hashtable();
                     Hashtable types = new Hashtable();
                     Histogram hist = new Histogram();
                     LineReader reader = new LineReader(new BufferedReader(new InputStreamReader(new FileInputStream(inputName))));
                     StringTable strings = new StringTable();
                     String line = reader.readLine();
                     while (line != null) {
                            if (line.startsWith("0x")) {
                                   String addr = strings.intern(line.substring(0, 10));
                                   String name = strings.intern(line.substring(line.indexOf('<') + 1, line.indexOf('>')));
                                   int size;
                                   try {
                                          String str = line.substring(line.indexOf('(') + 1, line.indexOf(')')).trim();
                                          size = Integer.parseInt(str);
                                   } catch (NumberFormatException nfe) {
                                          size = 0;
                                   }

                                   // generate a unique type for this object.
                                   String key = strings.intern(name + "_" + size);
                                   Type type = (Type) types.get(key);
                                   if (type == null) {
                                          type = new Type(name, size);
                                          types.put(key, type);
                                   }
                                   
                                   // read in fields. could compress these by converting to Integer objects.
                                   vec.setSize(0);
                                   for (line = reader.readLine(); line != null && line.charAt(0) == '\t'; line = reader.readLine())
                                          vec.addElement(strings.intern(line.substring(1, 11)));
                                   Object[] refs = new Object[vec.size()];
                                   vec.copyInto(refs);
                                   vec.setSize(0);
                                   
                                // record the offset of the stack crawl, which will be read in and formatted at the end, to save memory.
                                   long crawlOffset = reader.offset;
                                   short crawlCount = 0;
                                   for (line = reader.readLine(); line != null && !line.startsWith("Leaked "); line = reader.readLine())
                                          ++crawlCount;

                                   // record the leak.
                                   leakTable.put(addr, new Leak(addr, type, refs, crawlOffset, crawlCount));

                                   // count the leak types in a histogram.
                                   hist.record(type);
                            } else {
                                   line = reader.readLine();
                            }
                     }
                     reader.close();
                     
                     // don't need the interned strings table anymore.
                     strings = null;
                     
                     Leak[] leaks = new Leak[leakTable.size()];
                     int leakCount = 0;
                     long totalSize = 0;

                     Hashtable parentTable = new Hashtable();

                     // now, we have a table full of leaked objects, lets derive reference counts, and build the graph.
                     Enumeration e = leakTable.elements();
                     while (e.hasMoreElements()) {
                            Leak leak = (Leak) e.nextElement();
                            Object[] refs = leak.mReferences;
                            int count = refs.length;
                            for (int r = 0; r < count; ++r) {
                                   String addr = (String) refs[r];
                                   Leak ref = (Leak) leakTable.get(addr);
                                   if (ref != null) {
                                          // increase the ref count.
                                          ref.mRefCount++;
                                          // change string to ref itself.
                                          refs[r] = ref;
                                          // add leak to ref's parents vector.
                                          Vector parents = (Vector) parentTable.get(ref);
                                          if (parents == null) {
                                                 parents = new Vector();
                                                 parentTable.put(ref, parents);
                                          }
                                          parents.addElement(leak);
                                   }
                            }
                            leaks[leakCount++] = leak;
                            totalSize += leak.mType.mSize;
                     }

                     // be nice to the GC.
                     leakTable.clear();
                     leakTable = null;

            // sort the leaks by address, and find interior pointers.
            {
                QuickSort byAddress = new QuickSort(new Reference.ByAddress());
                byAddress.sort(leaks);
            }
            
            for (int i = 0; i < leakCount; ++i) {
                Leak leak = leaks[i];
                Object[] refs = leak.mReferences;
                int count = refs.length;
                short childCount = 0;
                for (int r = 0; r < count; ++r) {
                    if (refs[r] instanceof String) {
                        String addr = (String) refs[r];
                        if (addr.equals("0x00000000")) continue;
                        int address = (int) Long.parseLong(addr.substring(2), 16);
                        Leak ref = (Leak) Reference.findNearest(leaks, address);
                        if (ref != null) {
                                          // increase the ref count.
                                          ref.mRefCount++;
                                          // change string to ref itself.
                                          refs[r] = ref;
                                              // add leak to ref's parents vector.
                                          Vector parents = (Vector) parentTable.get(ref);
                                          if (parents == null) {
                                                 parents = new Vector();
                                                 parentTable.put(ref, parents);
                                          }
                                          parents.addElement(leak);
                                          ++childCount;
                        }
                    } else {
                        ++childCount;
                    }
                }
                leak.mChildCount = childCount;
            }
                     
                     // set the parents of each leak.
                     e = parentTable.keys();
                     while (e.hasMoreElements()) {
                            Leak leak = (Leak) e.nextElement();
                            Vector parents = (Vector) parentTable.get(leak);
                            if (parents != null)
                                   leak.setParents(parents);
                     }
                     
                     // be nice to the GC.
                     parentTable.clear();
                     parentTable = null;
                     
                     // store the leak report in inputName + ".html"
                     PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(inputName + ".html"))));

                     Date now = new Date();
                     out.println("<TITLE>Leaks as of " + now + "</TITLE>");

            // print leak summary.
            out.println("<H2>Leak Summary</H2>");
            out.println("total objects leaked = " + leakCount + "<BR>");
            out.println("total memory leaked  = " + totalSize + " bytes.<BR>");

              printLeakHistogram(out, hist);
               printLeakStructure(out, leaks);

                     // open original file again, as a RandomAccessFile, to read in stack crawl information.
                     
                     // print the leak report.
                     if (!ROOTS_ONLY) {
                     RandomAccessFile in = new RandomAccessFile(inputName, "r");
                            printLeaks(in, out, leaks);
                            in.close();
                     }
                     
                     out.close();
              } catch (Exception e) {
                     e.printStackTrace(System.err);
              }
       }

Here is the call graph for this function:

Here is the caller graph for this function:

static void leaksoup.main ( String[]  args) [inline, static]

Definition at line 244 of file leaksoup.java.

                                              {
              if (args.length == 0) {
                     System.out.println("usage:  leaksoup [-blame] [-lxr] [-assign] [-roots] leaks");
                     System.exit(1);
              }
              
              // assume user want's blame URLs.
              FileLocator.USE_BLAME = true;
              FileLocator.ASSIGN_BLAME = false;
              ROOTS_ONLY = false;
              
              for (int i = 0; i < args.length; i++) {
                     String arg = args[i];
                     if (arg.charAt(0) == '-') {
                            if (arg.equals("-blame"))
                                   FileLocator.USE_BLAME = true;
                            else if (arg.equals("-lxr"))
                                   FileLocator.USE_BLAME = false;
                            else if (arg.equals("-assign"))
                                   FileLocator.ASSIGN_BLAME = true;
                            else if (arg.equals("-roots"))
                                   ROOTS_ONLY = true;
                            else
                                   System.out.println("unrecognized option: " + arg);
                     } else {
                            cook(arg);
                     }
              }
              
              // quit the application.
              System.exit(0);
       }

Here is the call graph for this function:

static void leaksoup.printField ( PrintWriter  out,
Object  field 
) [inline, static, package]

Definition at line 552 of file leaksoup.java.

                                                             {
              String value = field.toString();
              if (field instanceof String) {
                     // this is just a plain HEX value, print its contents as ASCII as well.
                     if (value.startsWith("0x")) {
                            try {
                                   int hexValue = Integer.parseInt(value.substring(2), 16);
                                   // don't interpret some common values, to save some space.
                                   if (hexValue != 0 && hexValue != -1) {
                                          StringBuffer buffer = new StringBuffer(value);
                                          buffer.append('\t');
                                          appendChar(buffer, ((hexValue >>> 24) & 0x00FF));
                                          appendChar(buffer, ((hexValue >>> 16) & 0x00FF));
                                          appendChar(buffer, ((hexValue >>>  8) & 0x00FF));
                                          appendChar(buffer, (hexValue & 0x00FF));
                                          value = buffer.toString();
                                   }
                            } catch (NumberFormatException nfe) {
                            }
                     }
              }
              out.println("\t" + value);
       }

Here is the call graph for this function:

Here is the caller graph for this function:

static void leaksoup.printLeakHistogram ( PrintWriter  out,
Histogram  hist 
) throws IOException [inline, static, package]

Definition at line 468 of file leaksoup.java.

                                                                                          {
              // sort the types by histogram count.
              Object[] types = hist.objects();
              QuickSort byTypeBinSize = new QuickSort(new ByTypeBinSize(hist));
              byTypeBinSize.sort(types);
              
              out.println("<H2>Leak Histogram</H2>");
              out.println("<PRE>");
              int index = types.length;
              while (index > 0) {
                     Type type = (Type) types[--index];
                     int count = hist.count(type);
                     out.println(type.toString() + " : " + count + " {" + (count * type.mSize) + "}");
              }
              out.println("</PRE>");
       }

Here is the call graph for this function:

Here is the caller graph for this function:

static void leaksoup.printLeaks ( RandomAccessFile  in,
PrintWriter  out,
Leak[]  leaks 
) throws IOException [inline, static, package]

Definition at line 576 of file leaksoup.java.

                                                                                                     {
              // sort the leaks by total size.
              QuickSort bySize = new QuickSort(new Leak.ByTotalSize());
              bySize.sort(leaks);

              // now, print the report, sorted by type size.
              out.println("<PRE>");
              Type anchorType = null;
        int leakCount = leaks.length;
              for (int i = 0; i < leakCount; ++i) {
                     Leak leak = leaks[i];
                     if (anchorType != leak.mType) {
                            anchorType = leak.mType;
                            out.println("\n<HR>");
                            out.println("<A NAME=\"" + anchorType.mName + "_" + anchorType.mSize + "\"></A>");
                            out.println("<H3>" + anchorType + " Leaks</H3>");
                     }
                     out.println("<A NAME=\"" + leak.mName + "\"></A>");
                     if (leak.mParents != null) {
                            out.print(leak);
                            out.println(" <A HREF=\"#" + leak.mName + "_parents\">parents</A>");
                     } else {
                            out.println(leak);
                     }
                     // print object's fields:
                     Object[] refs = leak.mReferences;
                     int count = refs.length;
                     for (int j = 0; j < count; j++)
                            printField(out, refs[j]);
                     // print object's stack crawl:
                     in.seek(leak.mCrawlOffset);
                     short crawlCount = leak.mCrawlCount;
                     while (crawlCount-- > 0) {
                         String line = in.readLine();
                            String location = FileLocator.getFileLocation(line);
                            out.println(location);
                     }
                     // print object's parents.
                     if (leak.mParents != null) {
                            out.println("<A NAME=\"" + leak.mName + "_parents\"></A>");
                            out.println("\nLeak Parents:");
                            Leak[] parents = leak.mParents;
                            count = parents.length;
                            for (int j = 0; j < count; j++)
                                   out.println("\t" + parents[j]);
                     }
              }
              out.println("</PRE>");
       }

Here is the call graph for this function:

Here is the caller graph for this function:

static void leaksoup.printLeakStructure ( PrintWriter  out,
Leak[]  leaks 
) [inline, static, package]

Definition at line 485 of file leaksoup.java.

                                                                     {
        // print root leaks. consider only leaks with a reference
        // count of 0, which when fixed, will hopefully reclaim
        // all of the objects below them in the graph.
        {
            QuickSort byRefCount = new QuickSort(new Leak.ByRefCount());
            byRefCount.sort(leaks);
        }
        
        int rootCount = 0;
        int leakCount = leaks.length;
        for (int i = 0; i < leakCount; ++i) {
            Leak leak = leaks[i];
            if (leak.mRefCount > 0)
                break;
            ++rootCount;
            leak.computeTotalSize();
        }

        {
            QuickSort byTotalSize = new QuickSort(new Leak.ByTotalSize());
            byTotalSize.sort(leaks, rootCount);
        }

        out.println("<H2>Leak Roots</H2>");
        out.println("<PRE>");
        for (int i = 0; i < rootCount; ++i) {
            Leak leak = leaks[i];
            leak.printGraph(out);
        }
        out.println("</PRE>");

        // print leak cycles. traverse the leaks from objects with most number
        // of children to least, so that leaf objects will be printed after
        // their parents.
        {
            QuickSort byChildCount = new QuickSort(new Leak.ByChildCount());
            byChildCount.sort(leaks);
        }
        
        out.println("<H2>Leak Cycles</H2>");
        out.println("<PRE>");
        for (int i = 0; i < leakCount; ++i) {
            Leak leak = leaks[i];
            // if an object's total size isn't known yet, then it must
            // be a member of a cycle, since it wasn't reached when traversing roots.
            if (leak.mTotalSize == 0) {
                leak.computeTotalSize();
                leak.printCycle(out);
            }
        }
        out.println("</PRE>");
       }

Here is the call graph for this function:

Here is the caller graph for this function:


Member Data Documentation

boolean leaksoup.ROOTS_ONLY = false [static, private]

Definition at line 242 of file leaksoup.java.


The documentation for this class was generated from the following file: