EMMA Coverage Report (generated Sat Jun 02 16:47:50 EDT 2012)
[all classes][net.sf.madmap]

COVERAGE SUMMARY FOR SOURCE FILE [Madmap.java]

nameclass, %method, %block, %line, %
Madmap.java100% (1/1)68%  (28/41)53%  (2629/4964)61%  (518.3/856)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class Madmap100% (1/1)68%  (28/41)53%  (2629/4964)61%  (518.3/856)
Madmap (File, MainWindow): void 0%   (0/1)0%   (0/174)0%   (0/41)
Madmap (String, MainWindow): void 0%   (0/1)0%   (0/163)0%   (0/35)
doRetainedByClass (): void 0%   (0/1)0%   (0/154)0%   (0/29)
dumpCollectedInfo (boolean, boolean, boolean, boolean, boolean): void 0%   (0/1)0%   (0/211)0%   (0/49)
getFilename (): String 0%   (0/1)0%   (0/3)0%   (0/1)
getMsg (): String 0%   (0/1)0%   (0/2)0%   (0/1)
getVerbose (): boolean 0%   (0/1)0%   (0/2)0%   (0/1)
iterativeCollectChildrenSizeOld (HprofHeapCollectable): void 0%   (0/1)0%   (0/339)0%   (0/51)
recursiveCollectChildrenSize (HprofHeapCollectable): long 0%   (0/1)0%   (0/120)0%   (0/23)
run (): void 0%   (0/1)0%   (0/174)0%   (0/17)
setFile (File): void 0%   (0/1)0%   (0/3)0%   (0/2)
setVerbose (boolean): void 0%   (0/1)0%   (0/3)0%   (0/1)
sortOnRetainedSize (Vector, String): void 0%   (0/1)0%   (0/170)0%   (0/34)
accumulateChildrenSize (HprofHeapCollectable): void 100% (1/1)35%  (46/131)76%  (13.6/18)
iterativeMarking (): void 100% (1/1)47%  (88/187)50%  (14.5/29)
iterativeSortOnRetainedSize (Vector, String): void 100% (1/1)48%  (93/195)55%  (19.3/35)
iterativeCollectChildrenSize (HprofHeapCollectable): void 100% (1/1)49%  (153/312)81%  (42.1/52)
getRefFromAddr (long): HprofHeapCollectable 100% (1/1)65%  (24/37)75%  (4.5/6)
buildLiveObjectsHistogram (): void 100% (1/1)69%  (178/258)79%  (39.7/50)
isBinaryDump (String): boolean 100% (1/1)71%  (47/66)76%  (13.7/18)
buildLiveObjectsTable (): void 100% (1/1)76%  (426/561)81%  (79.9/99)
init (): void 100% (1/1)77%  (24/31)88%  (7/8)
analyze (): void 100% (1/1)83%  (203/246)89%  (34.8/39)
getFakeArrayClass (String): HprofClassElement 100% (1/1)83%  (97/117)88%  (17.7/20)
printFinalizers (): void 100% (1/1)88%  (249/284)91%  (44.5/49)
markChildren (HprofHeapCollectable): void 100% (1/1)92%  (114/124)97%  (24.2/25)
<static initializer> 100% (1/1)97%  (56/58)100% (10/10)
displayRetainedSortResults (String): void 100% (1/1)98%  (329/337)98%  (65/66)
Madmap (String): void 100% (1/1)100% (160/160)100% (34/34)
elapsedTime (): float 100% (1/1)100% (8/8)100% (1/1)
getClasses (): ConcurrentHashMap 100% (1/1)100% (3/3)100% (1/1)
getGuesses (): ConcurrentHashMap 100% (1/1)100% (3/3)100% (1/1)
getObjects (): ConcurrentHashMap 100% (1/1)100% (3/3)100% (1/1)
getRoots (): Vector 100% (1/1)100% (3/3)100% (1/1)
getStackTraces (): ConcurrentHashMap 100% (1/1)100% (3/3)100% (1/1)
getThreads (): ConcurrentHashMap 100% (1/1)100% (3/3)100% (1/1)
getWindow (): MainWindow 100% (1/1)100% (3/3)100% (1/1)
isBinary (): boolean 100% (1/1)100% (3/3)100% (1/1)
preinit (String): void 100% (1/1)100% (147/147)100% (24/24)
reconcileBasicTypeArrays (): void 100% (1/1)100% (98/98)100% (23/23)
resetForScanning (): void 100% (1/1)100% (65/65)100% (19/19)

1/*
2 * Copyright 2008 Eric Caspole
3 * 
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
5 * file except in compliance with the License. You may obtain a copy of the License at
6 * 
7 * http://www.apache.org/licenses/LICENSE-2.0
8 * 
9 * Unless required by applicable law or agreed to in writing, software distributed under
10 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11 * KIND, either express or implied. See the License for the specific language governing
12 * permissions and limitations under the License.
13 */
14package net.sf.madmap;
15 
16import java.util.*;
17import java.util.concurrent.*;
18import java.io.*;
19 
20import javax.swing.JProgressBar;
21import javax.swing.JOptionPane;
22import java.lang.management.*; 
23import javax.management.*;
24 
25/**
26 * Madmap objects hold the file being read and run the analysis after being
27 * read in by the HprofReaders, which get started by the Madmap for the input
28 * file.
29 * 
30 * @author ecaspole
31 *
32 */
33public class Madmap  implements MadmapMBean, Runnable  {
34  static File  _hprofFile = null;
35  String  _fileName;
36  boolean _isBinary       = false;  
37  long    _startTime      = 0;
38  ILogger        _logger = (ILogger)(MadmapMain.appContext()).getBean("logger");
39  IResources        _resources = (IResources)(MadmapMain.appContext()).getBean("resources");  
40  IHprofReader        _reader = (IHprofReader)(MadmapMain.appContext()).getBean("reader");
41  IHprofReader        _binReader = (IHprofReader)(MadmapMain.appContext()).getBean("binReader");
42  
43  ConcurrentHashMap<HprofHeapAllocation,HprofHeapAllocation>    _heap_objects_table   = new ConcurrentHashMap<HprofHeapAllocation,HprofHeapAllocation>();
44  ConcurrentHashMap<HprofClassElement,HprofClassElement>        _class_list           = new ConcurrentHashMap<HprofClassElement,HprofClassElement>();
45 
46  ConcurrentHashMap   _leak_guess_table       = null; // new ConcurrentHashMap();
47  ConcurrentHashMap   _stack_trace_table      = new ConcurrentHashMap();
48  ConcurrentHashMap   _threads_list           = new ConcurrentHashMap();
49  Vector              _roots_list             = new Vector( 1024 );
50  ConcurrentHashMap   _finalizable_class_list = new ConcurrentHashMap();
51 
52  MainWindow                 _window;
53 
54  // MBean methods
55  public String getMsg()                  { return "Thanks for using the Madmap MBean."; } 
56    
57  public boolean  getVerbose()            { return MadmapMain.verbose(); }
58  public void     setVerbose(boolean x)   { MadmapMain.setVerbose(x); } 
59 
60  public String  getFilename()            { return _fileName; }
61  public boolean isBinary()               { return _isBinary; }
62  
63  // Basic type arrays do not know their class addr when they are seen,
64  // so they are reconciled during analysis to build 
65  // the type/count histogram.
66  HprofClassElement boolArrayKlass = null;
67  HprofClassElement byteArrayKlass = null;
68  HprofClassElement charArrayKlass = null;
69  HprofClassElement shortArrayKlass = null;
70  HprofClassElement intArrayKlass = null;
71  HprofClassElement longArrayKlass = null;
72  HprofClassElement floatArrayKlass = null;
73  HprofClassElement doubleArrayKlass = null;
74  
75  // fakeKlassAddrs are used to keep track of basic type array
76  // classes until all the classes are loaded, then arrays holding the
77  // fake type are patched with the real type addr
78  
79  static final int fakeBoolArrayKlassAddr = -1;
80  static final int fakeByteArrayKlassAddr = -2;
81  static final int fakeCharArrayKlassAddr = -3;
82  static final int fakeShortArrayKlassAddr = -4;
83  static final int fakeIntArrayKlassAddr = -5;
84  static final int fakeLongArrayKlassAddr = -6;
85  static final int fakeFloatArrayKlassAddr = -7;
86  static final int fakeDoubleArrayKlassAddr = -8;
87  
88  static final HprofClassElement fakeBoolArrayKlass = new HprofClassElement(fakeBoolArrayKlassAddr, "bool_fake_array_class");
89  static final HprofClassElement fakeByteArrayKlass = new HprofClassElement(fakeByteArrayKlassAddr, "byte_fake_array_class");
90  static final HprofClassElement fakeCharArrayKlass = new HprofClassElement(fakeCharArrayKlassAddr, "char_fake_array_class");
91  static final HprofClassElement fakeShortArrayKlass = new HprofClassElement(fakeShortArrayKlassAddr, "short_fake_array_class");
92  static final HprofClassElement fakeIntArrayKlass = new HprofClassElement(fakeIntArrayKlassAddr, "int_fake_array_class");
93  static final HprofClassElement fakeLongArrayKlass = new HprofClassElement(fakeLongArrayKlassAddr, "long_fake_array_class");
94  static final HprofClassElement fakeFloatArrayKlass = new HprofClassElement(fakeFloatArrayKlassAddr, "float_fake_array_class");
95  static final HprofClassElement fakeDoubleArrayKlass = new HprofClassElement(fakeDoubleArrayKlassAddr, "double_fake_array_class");
96 
97  public static HprofClassElement getFakeArrayClass( String nm ) {
98    HprofClassElement cls_addr = null;
99    if ((nm == "boolean[]") || (nm == "boolean") || (nm == "[Z")) {
100      cls_addr = fakeBoolArrayKlass;
101    } else if ((nm == "byte[]") || (nm == "byte") || (nm == "[B")) {
102      cls_addr = fakeByteArrayKlass;
103    } else if ((nm == "char[]") || (nm == "char") || (nm == "[C")) {
104      cls_addr = fakeCharArrayKlass;
105    } else if (( nm == "short[]") || (nm == "short") || (nm == "[S")) {
106      cls_addr = fakeShortArrayKlass;
107    } else if ((nm == "int[]") || (nm == "int") || (nm == "[I")) {
108      cls_addr = fakeIntArrayKlass;
109    } else if ((nm == "long[]") || (nm == "long") || (nm == "[J")) {
110      cls_addr = fakeLongArrayKlass;
111    } else if ((nm == "float[]") || (nm == "float") || (nm == "[F")) {
112      cls_addr = fakeFloatArrayKlass;
113    } else if ((nm == "double[]") || (nm == "double") || (nm == "[D")) {
114      cls_addr = fakeDoubleArrayKlass;
115    } else {
116      System.out.println( "### No match for basic type array: " + nm );
117      assert true == false : "should not reach here!";
118    }
119  
120    return cls_addr;
121  }
122 
123 
124  public static void setFile( File f ) {
125    _hprofFile = f;
126  }
127 
128  public ConcurrentHashMap<HprofHeapAllocation,HprofHeapAllocation> getObjects()       { return _heap_objects_table; }
129  public ConcurrentHashMap getGuesses()       { return _leak_guess_table; }
130 
131  public ConcurrentHashMap getStackTraces()    { return _stack_trace_table; }
132  public ConcurrentHashMap getThreads()     { return _threads_list; }
133  public Vector getRoots()          { return _roots_list; }
134  public ConcurrentHashMap<HprofClassElement,HprofClassElement> getClasses()       { return _class_list; }
135 
136  public float elapsedTime() {
137    return (float)(System.currentTimeMillis() - _startTime)/(float)1000.0;
138  }
139  
140  public void run() {
141    _logger.myLog( getWindow(),  "  " );
142    _logger.myLog( getWindow(),  "=================================================================================" );
143    _logger.myLog( getWindow(),  "Execution environment for this run:  " );
144    _logger.myLog( getWindow(),  "madmap version\t= " + _resources.getString("version") ); 
145    _logger.myLog( getWindow(),  "java version\t= " + System.getProperty ( "java.version" ) ); 
146    _logger.myLog( getWindow(),  "os name\t= " + System. getProperty ( "os.name" ) );
147    _logger.myLog( getWindow(),  "os version\t= " + System. getProperty ( "os.version" ) );
148    _logger.myLog( getWindow(),  "default locale\t= " + java.util.Locale.getDefault() );
149    _logger.myLog( getWindow(),  "cwd\t= " + System.getProperty("user.dir") );
150    _logger.myLog( getWindow(),  "Total memory\t= " + Runtime.getRuntime().totalMemory() );
151    _logger.myLog( getWindow(),  "Max memory\t= " + Runtime.getRuntime().maxMemory() );
152    _logger.myLog( getWindow(),  "Free memory\t= " + Runtime.getRuntime().freeMemory() );
153    _logger.myLog( getWindow(),  "Processors\t= " + Runtime.getRuntime().availableProcessors() );
154    _logger.myLog( getWindow(),  "=================================================================================" );
155    _logger.myLog( getWindow(),  "  " );
156    init();
157  }
158 
159  public void init()
160  {      
161          _startTime = System.currentTimeMillis();
162    if (isBinary()) {
163      _binReader.parse( this, _fileName );
164    } else{
165      _reader.parse( this, _fileName );
166    }
167          if ( MadmapMain.runDump() ) {
168                  dumpCollectedInfo( true, true, true, true, false);
169          }
170          analyze();    
171  }
172 
173  public void dumpCollectedInfo( boolean thds, boolean stacks, boolean roots, boolean classes, boolean objects  ) {
174    _logger.myLog( getWindow(),  "==================================================================================================== " );
175    _logger.myLog( getWindow(),  "Dumping tables... " );
176 
177    if ( thds == true ) {
178      // Threads
179      _logger.myLog( getWindow(),  "Dumping Threads... " );
180      Collection<HprofThreadData> htc = this.getThreads().values();
181      Iterator<HprofThreadData>   ihtc = htc.iterator();
182      while( ihtc.hasNext() ) {
183        HprofThreadData ho = ihtc.next();
184        _logger.myLog( getWindow(),  ho.toString() );
185      }
186      _logger.myLog( getWindow(),  "==================================================================================================== " );
187    }
188    
189    if ( stacks == true ) {
190      // Stack traces
191      _logger.myLog( getWindow(),  "Dumping Stack traces... " );
192      Collection<HprofStackTraceData> htc = this.getStackTraces().values();
193      Iterator<HprofStackTraceData>   ihtc = htc.iterator();
194      while( ihtc.hasNext() ) {
195        HprofStackTraceData sd = ihtc.next();
196        _logger.myLog( getWindow(),  sd.toString() );
197        
198      }
199      _logger.myLog( getWindow(),  "==================================================================================================== " );
200    }
201    
202    if ( roots == true ) {
203      // Roots
204      _logger.myLog( getWindow(),  "Dumping Roots... " );
205      for( int i = 0; i < this.getRoots().size(); i++ ) {
206        HprofRoot rt = (HprofRoot) this.getRoots().get(i);
207        _logger.myLog( getWindow(),  rt.toString() );
208        
209      }
210      _logger.myLog( getWindow(),  "==================================================================================================== " );
211    }
212    
213    if ( classes == true ) {
214      // Classes
215      _logger.myLog( getWindow(),  "Dumping Classes... " );
216      Collection<HprofClassElement> cc = this.getClasses().values();
217      Iterator<HprofClassElement>   icc = cc.iterator();
218      while( icc.hasNext() ) {
219        HprofClassElement ho = icc.next();
220        _logger.myLog( getWindow(),  ho.toString() );
221      }
222      _logger.myLog( getWindow(),  "==================================================================================================== " );
223    }
224    
225    try {
226    
227    if ( objects == true ) {
228      // Objects
229      _logger.myLog( getWindow(),  "Dumping Objects... " );
230      Collection<HprofHeapAllocation> hoc = this.getObjects().values();
231      Iterator<HprofHeapAllocation>   ihoc = hoc.iterator();
232      
233      while( ihoc.hasNext() ) {
234        HprofHeapAllocation ho = ihoc.next();
235        assert ho != null : "ho was null!";
236        _logger.myLog( getWindow(),  ho.toString() );
237      }
238      _logger.myLog( getWindow(),  "==================================================================================================== " );
239    }
240    
241    } catch (Exception e) {
242            e.printStackTrace();
243    }
244  }
245 
246 
247  long _live_objects      = 0;
248  long _liveObjectsSize   = 0;
249  long _totalObjectsSize  = 0;
250  long _total_finalizers  = 0;
251 
252  public void printFinalizers() {
253    Collection<HprofHeapAllocation>  hoc   = this.getObjects().values();
254    Iterator<HprofHeapAllocation>    ihoc  = hoc.iterator();
255    HprofHeapCollectable          ho    = null;
256 
257    _logger.myLog( getWindow(),  "==================================================================================================== " );
258 
259    while( ihoc.hasNext() ) {
260      ho = (HprofHeapCollectable)ihoc.next();
261      if ( ho instanceof HprofClassElement ) {
262        continue;
263      }
264 
265      if ( (((HprofHeapAllocation)ho).className()).equals("java.lang.ref.Finalizer") ||
266                      (((HprofHeapAllocation)ho).className()).equals("java/lang/ref/Finalizer")) {          
267        long referent;
268        HprofHeapAllocation horef     = null;
269 
270        _total_finalizers++;
271 
272        // In 1.4 referent is the third field, in 1.5 it is first
273        referent  = (ho.children())[ 2 ];          
274        horef     = ( HprofObject ) _heap_objects_table.get( new HprofHeapElement(referent) );
275        if ( ( horef.className().equals("java.lang.ref.Finalizer")) ) {
276          // It must be 1.5, get child 0 instead
277          referent  = (ho.children())[ 0 ];
278          horef     = (HprofObject) _heap_objects_table.get( new HprofHeapElement(referent) );
279        }
280 
281        assert referent != 0 : "finalizer referent is null!" ;
282        assert horef != null : "finalizer referent not found in heap!" ;
283        if ( MadmapMain.runDump() ) {
284            System.out.println( "## Finalizer referent: " + referent + " = " + horef.toString());
285        }
286        
287        // Build the sorted TreeSet for the GUI table
288        HprofClassElement currClass = horef.getActualClass();
289        HprofClassElement c2 = (HprofClassElement)_finalizable_class_list.get((int)currClass.addr());
290        if (c2 == null) {
291          _finalizable_class_list.put( (int)currClass.addr(), currClass );
292        } else {
293            assert c2 == currClass : "referent classes should match?";
294        }
295        
296        currClass.setFinalizableCount( currClass.getFinalizableCount() + 1 );
297        currClass.setFinalizableSize( currClass.getFinalizableSize() + horef.size() );
298      }
299    }
300    
301    java.util.ArrayList<HprofClassElement> fList = new java.util.ArrayList<HprofClassElement>();
302    //fList.addAll(this.getClasses().values());
303    fList.addAll(_finalizable_class_list.values());
304    Collections.sort(fList, new FinalizeComparator());
305        
306    if ( ! MadmapMain.noGUI() ) {
307      getWindow().addFinalizerHeapTab( fList );
308    }
309        
310    _logger.myLog( getWindow(),  "Summary of finalizable objects sorted by cumulative size: " );
311    _logger.myLog( getWindow(),  " " );
312    _logger.myLog( getWindow(),  "Size\t\tCount\t\tClass" );
313    _logger.myLog( getWindow(),  "==================================================================================================== " );
314 
315    Iterator<HprofClassElement>   ihoc3 = fList.iterator();
316    while( ihoc3.hasNext() ) {
317      HprofClassElement hk = ihoc3.next();
318      int   ic = hk.getFinalizableCount();
319      long  is = hk.getFinalizableSize();
320 
321      if ( ic > 0 ) {
322        _logger.myLog( getWindow(),  is + "\t\t" + ic + "\t\t" + hk.className() + "@" + Long.toHexString( hk.addr() ) );
323      }
324    }
325    _logger.myLog( getWindow(),  "==================================================================================================== " );
326    _logger.myLog( getWindow(),  " " );
327    _logger.myLog( getWindow(),  elapsedTime() + ": Total count of finalizers: " + _total_finalizers );    
328  }
329 
330 
331  public void buildLiveObjectsTable() {
332    long      totalSize  = this.getObjects().size();
333    long      size  = 0;
334    long      lowestHeapAddr    = (long) Long.MAX_VALUE; // HACK this is 64GB or so
335    long      highestHeapAddr   = 0;
336    HprofHeapAllocation   biggestObj     = null;
337    long                  biggestObjSize = 0;
338    HprofHeapAllocation   biggestArr     = null;
339    long                  biggestArrSize = 0;
340    long                  deadObjects = 0;
341    int                   progressCounter = 0;
342    JProgressBar          progress_bar    = null;
343    
344    if ( ! MadmapMain.noGUI() ) {
345      progress_bar = getWindow().getProgressBar();
346      getWindow().getLabelForProgressBar().setText("Removing Dead Objects");
347 
348      progress_bar.setMinimum(0);
349      progress_bar.setMaximum(this.getObjects().size() - 1);
350      progress_bar.setValue(0);
351      
352     getWindow().updateMemoryProgressBar();
353    }
354    
355    for (Enumeration e = this.getObjects().keys() ; e.hasMoreElements() ; ) {
356      Object theKey = e.nextElement();
357      HprofHeapAllocation ho = (HprofHeapAllocation) this.getObjects().get( theKey );
358      size = ho.size();            
359      long currObjAddr = ho.addr();
360 
361      if ( currObjAddr == 0 ) {
362        System.out.println( "Found 0 addr object?! = " + ho );
363        _logger.myLog( getWindow(),  ho.toString() );        
364      }
365 
366      // record heap range info      
367      if ( currObjAddr < lowestHeapAddr ) {
368        assert currObjAddr != 0 : "object addr is messed up." ;
369        lowestHeapAddr = currObjAddr;
370      }
371      if ( currObjAddr > highestHeapAddr ) {
372        highestHeapAddr = currObjAddr;
373      }
374            
375      _totalObjectsSize += size;
376      if ( ho.isAlive() ) {
377              
378        // fix the basic type arrays right away - it is necessary
379        // to print, etc.
380        // This doesnt seem like the best place to do this but it avoids 
381        // having another complete pass over the heap table
382        HprofClassElement klass_addr        = ho.class_addr();
383 
384        if ( klass_addr == fakeBoolArrayKlass ) {
385          ho.set_class_addr( boolArrayKlass );
386          assert ho instanceof HprofArrayObject : "Class is wrong for array type";
387        } else if ( klass_addr == fakeByteArrayKlass ) {
388          ho.set_class_addr( byteArrayKlass );
389          assert ho instanceof HprofArrayObject : "Class is wrong for array type";        
390        } else if ( klass_addr == fakeCharArrayKlass ) {
391          ho.set_class_addr( charArrayKlass );
392          assert ho instanceof HprofArrayObject : "Class is wrong for array type";        
393        } else if ( klass_addr == fakeShortArrayKlass ) {
394          ho.set_class_addr( shortArrayKlass );
395          assert ho instanceof HprofArrayObject : "Class is wrong for array type";        
396        } else if ( klass_addr == fakeIntArrayKlass ) {
397          ho.set_class_addr( intArrayKlass );
398          assert ho instanceof HprofArrayObject : "Class is wrong for array type";        
399        } else if ( klass_addr == fakeLongArrayKlass ) {
400          ho.set_class_addr( longArrayKlass );
401          assert ho instanceof HprofArrayObject : "Class is wrong for array type";        
402        } else if ( klass_addr == fakeFloatArrayKlass ) {
403          ho.set_class_addr( floatArrayKlass );
404          assert ho instanceof HprofArrayObject : "Class is wrong for array type";        
405        } else if ( klass_addr == fakeDoubleArrayKlass ) {
406          ho.set_class_addr( doubleArrayKlass );
407          assert ho instanceof HprofArrayObject : "Class is wrong for array type";        
408        }
409              
410        _live_objects++;
411        _liveObjectsSize += size;
412        
413        // record the largest live object and array while building live table
414        if ( ho instanceof HprofArrayObject ) {
415          if ( size > biggestArrSize ) {
416            biggestArr = (HprofHeapAllocation) ho;
417            biggestArrSize = size;
418          }
419        } else if ( (ho instanceof HprofObject) /* || (ho instanceof HprofClassElement) */ ) {
420          if ( size > biggestObjSize ) {
421            biggestObj = (HprofHeapAllocation) ho;
422            biggestObjSize = size;
423          }
424        } else {
425          _logger.myLog( getWindow(),  "Unknown instance: " );
426        _logger.myLog( getWindow(),  ho.toString() );          
427        }
428      } else {
429 
430        if ( MadmapMain.runDump() ) {
431          System.out.println( "Removed: " + ho.className() + "@" + Long.toHexString( ho.addr() ) );
432        }
433 
434        this.getObjects().remove( theKey );
435        deadObjects++;
436      }
437      
438      if( ( ! MadmapMain.noGUI() ) && ((progressCounter++) % 100 == 0)) {
439        progress_bar.setValue(progressCounter);
440        getWindow().updateMemoryProgressBar();        
441      }
442    }
443 
444    if ( ! MadmapMain.noGUI() ) {
445      progress_bar.setValue(progress_bar.getMaximum());
446      getWindow().updateMemoryProgressBar();
447    }
448    
449    _logger.myLog( getWindow(), "\n");
450    _logger.myLog( getWindow(),  "Objects in Heap:" );
451    _logger.myLog( getWindow(),  " Total       : " + totalSize );
452    _logger.myLog( getWindow(),  " Total size  : " + _totalObjectsSize );
453    _logger.myLog( getWindow(),  " Live        : " + _live_objects );
454    _logger.myLog( getWindow(),  " Live size   : " + _liveObjectsSize );
455    _logger.myLog( getWindow(),  " Unreferenced: " + ( totalSize - _live_objects ));
456    _logger.myLog( getWindow(),  " Removed     : " + deadObjects );
457    _logger.myLog( getWindow(),  " Lowest object start address : " + Long.toHexString(lowestHeapAddr) );
458    _logger.myLog( getWindow(),  " Highest object start address: " + Long.toHexString(highestHeapAddr) );
459    _logger.myLog( getWindow(),  " Size of heap range          : 0x" + Long.toHexString(highestHeapAddr - lowestHeapAddr) + " == " + (highestHeapAddr - lowestHeapAddr));
460    
461    if ( biggestObj != null ) {
462      _logger.myLog( getWindow(),  "Biggest Array:" );
463      
464      _logger.myLog( getWindow(),  new String(Long.toHexString(biggestArr.addr()) + " " + biggestArr.className() + " size=" + biggestArr.size()));
465      //if ( MadmapMain.verbose()) {
466      if ( false ) {
467            _logger.myLog( getWindow(),  biggestArr.toString() );
468              _logger.myLog( getWindow(), "\n");
469      }
470      _logger.myLog( getWindow(),  "Biggest Object:" );
471      _logger.myLog( getWindow(),  biggestObj.toString() );
472    }
473  }
474 
475 
476  int _totalMarkedLive = 0;
477  java.util.Stack<HprofHeapElement> _marking_stack = new java.util.Stack<HprofHeapElement>();
478 
479 
480  // This will be called with roots with iterative marking
481  public void markChildren( HprofHeapCollectable ho ) {
482    int markedInThisPass  = 0;
483  
484    assert _marking_stack.empty() : "starting markChildren but _marking_stack is not empty! " ;
485 
486    if ( ! ho.isAlive() ) {
487      ho.setLiveness( true );
488      _totalMarkedLive++;
489      markedInThisPass++;
490      
491      //if ( MadmapMain.runDump() ) {
492      //  System.out.println( "markChildren: root: " + ho.className() + "@" + Long.toHexString( ho.addr() ) );
493      //}
494      
495      // Add the children of this root
496      long numChildren = ho.children_size();
497      for ( int i = 0; i < numChildren; i++ ) {
498        _marking_stack.push( new HprofHeapElement( (long)ho.children()[i] ));
499      }
500      
501      // In a loop, keep marking and adding children going down from this root
502      while ( ! _marking_stack.empty() ) {
503        
504        // Get the long that is a heap ref
505        HprofHeapElement addr  = (HprofHeapElement)_marking_stack.pop();
506        
507        // See if it is in the heap table
508        HprofHeapCollectable  child = (HprofHeapCollectable) this.getObjects().get( addr );
509        
510        // It could be a class ref
511        if ( child == null ) {
512          //if ( MadmapMain.verbose() ) {
513          //  System.out.println( "Object " + ho.addr() + " " + " child: " + j + " is null!" );
514          //}
515          child = (HprofHeapCollectable) this.getClasses().get( addr );
516        }
517        
518        if ( child == null ) {
519          //if ( MadmapMain.verbose() ) {
520          //  _logger.myLog( getWindow(),  "markChildren: Cannot find child " + Long.toHexString( addr.addr() ) + " descending from root " + Long.toHexString(ho.addr()) + " in heap table!!" );
521          //  _logger.myLog( getWindow(),  ho.toString() );
522          //}
523        } else {
524          // Add and mark objects only once
525          if ( ! child.isAlive() ) {
526            child.setLiveness( true );
527            _totalMarkedLive++;
528            markedInThisPass++;
529            
530            // Add the children of this object
531            numChildren = child.children_size();
532            for ( int i = 0; i < numChildren; i++ ) {
533              _marking_stack.push( new HprofHeapElement(child.children()[i]) );
534            }
535          }
536        }
537      }
538    } else {
539      //if ( verbose() ) {
540      //  System.out.println( "markChildren: root was already marked: " + ho.className() + "@" + Long.toHexString( ho.addr() ) );
541      //  ho.print();
542      //}
543    
544    }
545    //if ( markedInThisPass > 1 ) {
546    //  System.out.println( "markedInThisPass: " + markedInThisPass );
547    //}
548    
549    assert _marking_stack.empty() : "exiting markChildren but _marking_stack is not empty! " ;
550  }
551 
552 
553  private void iterativeMarking() {
554    JProgressBar progress_bar   = null;
555  
556    try {
557 
558      _logger.myLog( getWindow(),  elapsedTime() + ": analyze: iterative marking" );
559 
560      if ( ! MadmapMain.noGUI() ) {
561        progress_bar = getWindow().getProgressBar();
562        getWindow().getLabelForProgressBar().setText("Marking Live Objects");
563        progress_bar.setMinimum(0);
564        progress_bar.setMaximum(this.getRoots().size() - 1);
565        progress_bar.setValue(0);
566      }
567    
568      // Do marking and analysis by looping-marking method
569      {
570        for ( int i = 0; i < this.getRoots().size(); i++ ) {
571          HprofHeapCollectable ho;
572          
573          // Get root from class list
574          ho = (HprofHeapCollectable) this.getClasses().get( new HprofHeapElement(((HprofRoot)this.getRoots().get(i)).addr()) );
575 
576          // otherwise get root from objects table
577          if ( ho == null ) {
578            ho = (HprofHeapCollectable) this.getObjects().get( new HprofHeapElement( ((HprofRoot)this.getRoots().get(i)).addr() ));
579          }
580          
581          if ( ho != null ) {
582            markChildren( ho );
583          } else {
584            // The 0 root is the primordial root
585            if (i != 0 && MadmapMain.verbose() && (((HprofRoot)this.getRoots().get(i)).rootType().equals("<system class>"))) {
586              _logger.myLog( getWindow(),  "# Cannot find system class root[" + i + "]: " + this.getRoots().get(i) + " in heap table or in class list!!" );
587              _logger.myLog( getWindow(),   ((HprofRoot)this.getRoots().get(i)).toString() );
588            }
589          }
590 
591          if( ( ! MadmapMain.noGUI() ) && (i % 100 == 0)) {
592            progress_bar.setValue(i);
593            getWindow().updateMemoryProgressBar();            
594          }
595        }
596 
597        if( ! MadmapMain.noGUI() ) {
598          progress_bar.setValue(progress_bar.getMaximum());
599        }
600        _logger.myLog( getWindow(),  elapsedTime() + ": analyze: iterative marking complete" );
601      
602        // Done marking, dump the _marking_stack
603        _marking_stack = null;
604      }
605      
606    } catch( Throwable e ) {
607      _logger.myLog( getWindow(),  elapsedTime() + ": Exception in iterativeMarking(): " + e );
608      e.printStackTrace();
609    }
610  }
611 
612 
613  int _maxRecursion  = 0;
614  int _currRecursion = 0;
615 
616  public long recursiveCollectChildrenSize( HprofHeapCollectable ho ) {
617    ho.setLiveness( true );
618    ho.setRetainedSize( ho.size() );
619    _totalMarkedLive++;
620    long numChildren = ho.children_size();
621    if ( numChildren > 0 ) {
622      long[] curr_children = ho.children();
623 
624      //if ( MadmapMain.verbose() ) {
625      //  System.out.println( "Object " + ho.addr() + " " + " children: " + numChildren );
626      //}
627      for ( int j = 0; j < numChildren; j++ ) {
628        try { 
629          long                  addr  = curr_children[ j ];
630          HprofHeapCollectable  child = (HprofHeapAllocation) this.getObjects().get( new HprofHeapElement(addr) );
631 
632          // It could be a class ref
633          if ( child == null ) {
634            //if ( MadmapMain.verbose() ) {
635            //  System.out.println( "Object " + ho.addr() + " " + " child: " + j + " is null!" );
636            //}
637            child = (HprofHeapCollectable) this.getClasses().get( new HprofHeapElement(addr) );
638          }
639          
640          if ( child == null ) {
641            if ( MadmapMain.verbose() ) {
642              _logger.myLog( getWindow(),  "Cannot find child ho.children[" + j + "]: " + Long.toHexString( addr )  + " of parent " + Long.toHexString(ho.addr() ) + " in heap table!!" );
643              _logger.myLog( getWindow(),  ho.toString() );
644            }
645          } else {
646            if ( ! child.isAlive() ) {
647              long retSize = recursiveCollectChildrenSize( child );
648              ho.setRetainedSize(ho.getRetainedSize() + retSize);
649            }
650          }
651        } catch ( ClassCastException cce ) {
652          cce.printStackTrace();
653        }
654      }
655    }
656    _currRecursion++;
657    return ho.getRetainedSize();
658  }
659 
660   /**
661    * Build a histogram of types to make a table in the gui
662    */
663  private void buildLiveObjectsHistogram() {
664    Collection<HprofHeapAllocation> hoc = _heap_objects_table.values();
665    Iterator<HprofHeapAllocation>   ihoc = hoc.iterator();
666    while( ihoc.hasNext() ) {
667      HprofHeapAllocation ho  = ihoc.next();
668      HprofClassElement  klassRef        = ho.class_addr();
669      assert klassRef != null : "should not be null";
670      try {    
671        //System.out.println( "... " + ho.className() + "... " + Long.toHexString(ho.class_addr().addr()) + "... " + 
672        //    Long.toHexString(currObjAddr) + "    sz:" + size );
673        if ( klassRef != null ) {
674          klassRef.setInstanceCount( klassRef.getInstanceCount() + 1 );
675          klassRef.setInstanceSize( klassRef.getInstanceSize() + ho.size() );
676          //System.out.println( "Updating instance count for " + k.className() + "@" + Long.toHexString( k.addr() ) + " sz:" + ho.size() + " total sz:" + k.getInstanceSize());
677        } else {
678          _logger.myLog( getWindow(),  "no klass for " + Long.toHexString( klassRef.addr() ) + ho );
679        }      
680      } catch ( Exception e ) {
681        _logger.myLog( getWindow(),  "### Exception during basic type reconciliation " );
682        if ( ho != null ) {
683          _logger.myLog( getWindow(),  ho.toString() );
684        }
685        _logger.myLog( getWindow(),  "### klassRef = " + klassRef );
686        e.printStackTrace();
687      }
688    }
689        
690    java.util.ArrayList<HprofClassElement> classList = new java.util.ArrayList<HprofClassElement>();
691    classList.addAll(this.getClasses().values());    
692    Collections.sort(classList, new SizeComparator());
693    
694    // remove those with 0 instances
695    Iterator<HprofClassElement>   icl = classList.iterator();
696    while( icl.hasNext() ) {
697      HprofClassElement hk = icl.next();
698      int   ic = hk.getInstanceCount();
699      if (ic == 0) {
700        icl.remove();
701        if ( MadmapMain.runDump() ) {
702          System.out.println( "Removed class with 0 instances: " + hk.className() + "@" + Long.toHexString(hk.addr()));
703        }
704      }
705    }
706    
707    TreeSet threadSet = new TreeSet( new ThreadComparator() );
708    threadSet.addAll( (Collection<HprofThreadData>)_threads_list.values() );
709 
710    if ( ! MadmapMain.noGUI() ) {
711      getWindow().addLiveHeapTab( classList, _liveObjectsSize );
712      getWindow().addThreadsTab( threadSet );
713    }
714    
715    //_logger.myLog( getWindow(),  " " );
716    _logger.myLog( getWindow(),  "Summary of live objects sorted by cumulative size: " );
717    _logger.myLog( getWindow(),  " " );
718    _logger.myLog( getWindow(),  "Size\t\tPct of Live Size\t\tCount\t\tClass@ClassAddr" );
719    _logger.myLog( getWindow(),  "==================================================================================================== " );
720 
721    Iterator<HprofClassElement>   ihoc3 = classList.iterator();
722    while( ihoc3.hasNext() ) {
723      HprofClassElement hk = ihoc3.next();
724      int   ic = hk.getInstanceCount();
725      long  is = hk.getInstanceSize();
726      
727      float pctLiveSize =  (float) is / (float) _liveObjectsSize  *  (float)100.0;
728      
729      if ( ic > 0 ) {
730        _logger.myLog( getWindow(),  is + "\t\t" + pctLiveSize + "%\t\t" + ic + "\t\t" + hk.className() + "@" + Long.toHexString( hk.addr() ) );
731      }
732    }
733    _logger.myLog( getWindow(),  "==================================================================================================== " );
734  }
735  
736  /**
737   * Recursive version of retained size collection
738   * Only used with -r
739   * @param rootSet
740   * @param description
741   */
742  void sortOnRetainedSize( Vector rootSet, String description) {
743    JProgressBar progress_bar   = null;
744    int i = 0;
745    try {
746      Iterator<HprofRoot>   irs = rootSet.iterator();
747      
748      if ( ! MadmapMain.noGUI() ) {
749        progress_bar = getWindow().getProgressBar();
750        getWindow().getLabelForProgressBar().setText("Retained Size: " + description);
751        progress_bar.setMinimum(0);
752        progress_bar.setMaximum(rootSet.size() - 1);
753        progress_bar.setValue(0);
754      }
755      
756      _logger.myLog( getWindow(),  elapsedTime() + ": analyze: recursive retained size" );
757 
758      while( irs.hasNext() ) {
759        HprofRoot             hr  = irs.next();
760        HprofHeapCollectable  ho;
761        
762        ho = (HprofHeapCollectable) this.getClasses().get( new HprofHeapElement(hr.addr()) );
763        if ( ho == null ) {
764          ho = (HprofHeapCollectable) this.getObjects().get( new HprofHeapElement(hr.addr()) );
765        }
766 
767        if ( ho != null  ) {
768          recursiveCollectChildrenSize( ho );
769          if ( _currRecursion > _maxRecursion ) {
770            _maxRecursion  = _currRecursion;
771          }
772          _currRecursion = 0;        
773        } else {
774          // The 0 root is the primordial root
775            if (hr.addr() != 0 && MadmapMain.verbose() && hr.rootType().equals("<system class>")) {
776            _logger.myLog( getWindow(),  "Cannot find system class root[" + Long.toHexString(hr.addr()) + "] in heap table or in class list!!" );
777            _logger.myLog( getWindow(),  hr.toString() );            
778          }
779        }
780        
781        if (( ! MadmapMain.noGUI() ) && (i++ % 100 == 0)) {
782          progress_bar.setValue(i);
783          getWindow().updateMemoryProgressBar();
784        }
785      }
786 
787      if( ! MadmapMain.noGUI() ) {
788        progress_bar.setValue(progress_bar.getMaximum());
789      }      
790    } catch ( Exception e ) {
791      System.out.println( "Exception while collect children size = " + e );
792      e.printStackTrace();
793    }      
794  }
795 
796  /**
797   *        Reset object fields used repeatedly during retained size 
798   *        collection passes 
799   */
800  void resetForScanning() {
801    // Erase the liveness field, we use use it during size collection
802    for (Enumeration e = this.getObjects().keys() ; e.hasMoreElements() ; ) {
803      Object k = e.nextElement();
804      HprofHeapCollectable ho = (HprofHeapCollectable) this.getObjects().get( k );
805      ho.setLiveness(false);
806      ho.setRetainedSize(0);
807      ho.resetVisited();
808      ho.setClaimed(false);
809    }
810    for (Enumeration e = this.getClasses().keys() ; e.hasMoreElements() ; ) {
811      Object k = e.nextElement();
812      HprofClassElement ho = (HprofClassElement) this.getClasses().get( k );
813      ho.setLiveness(false);
814      ho.setRetainedSize(0);
815      ho.setTotalRetainedSize(0);
816      ho.resetVisited();
817      ho.setClaimed(false);
818    }
819    _leak_guess_table       = new ConcurrentHashMap();
820  }
821 
822  /**
823   * Returns the object for the given address in the target dump
824   * @param ref
825   * @return
826   */
827  HprofHeapCollectable getRefFromAddr( long ref ) {
828    // See if it is in the heap table
829    HprofHeapCollectable  child = (HprofHeapAllocation) this.getObjects().get( new HprofHeapElement( ref ));
830    // It could be a class ref
831    if ( child == null ) {
832      child = (HprofHeapCollectable) this.getClasses().get( new HprofHeapElement(ref) );
833    }    
834    if ( MadmapMain.runDump() && child == null ) {
835      System.out.println( "### getRefFromAddr didnt find " + Long.toHexString( ref ));
836    }
837    return child;
838  }
839 
840  void accumulateChildrenSize( HprofHeapCollectable ref )  {
841    // Collect the visited children sizes into ref
842    Stack visited = ref.getVisitedStack();
843    if ( visited != null ) {
844      while ( ! visited.empty() ) {
845        HprofHeapCollectable childRef = (HprofHeapCollectable) visited.pop();
846        
847        if ( ! childRef.isClaimed() ) {
848          childRef.claim();
849          long childSize = childRef.getRetainedSize();
850          ref.setRetainedSize( ref.getRetainedSize() + childSize);
851          if ( ! (ref.getRetainedSize() < _liveObjectsSize)) {
852            _logger.myLog( getWindow(),  "ret size > total live size of " + _liveObjectsSize );
853            _logger.myLog( getWindow(),  ref.toString() );            
854          }
855          if ( MadmapMain.runDump() ) {
856            System.out.println( "added " + childRef.className() + "@" + Long.toHexString( childRef.addr() ) + "=" + childSize +
857              " to:" + ref.className() + "@" + Long.toHexString( ref.addr() ) + " total size:" + ref.getRetainedSize() );
858          }
859        }
860      }
861    }
862    
863    if ( MadmapMain.runDump() ) {
864      System.out.println( "Completed retained size collection " + ref.className() + "@" + 
865          Long.toHexString( ref.addr() ) + " total size:" + ref.getRetainedSize()  );
866    }
867    assert ref.getRetainedSize() < _liveObjectsSize : "ret size > total live size!";
868  }
869  
870  public void iterativeCollectChildrenSize( HprofHeapCollectable ho ) {
871    int markedInThisPass  = 0;
872    java.util.Stack _addr_stack = new java.util.Stack();
873 
874    _addr_stack.push( ho );
875    
876    // In a loop, keep marking and adding children going down from this root
877    while ( ! _addr_stack.empty() ) {      
878      // Get the long that is a heap ref
879      HprofHeapCollectable  ref   = (HprofHeapCollectable)_addr_stack.pop();
880      //if ( MadmapMain.runDump() ) {
881      //  System.out.println( "popped ref: " + ref.className() + "@" +Long.toHexString( ref.addr() ));
882      //}
883 
884      if ( ref != null ) {
885        ref.setLiveness( true );        
886        
887        // Add the children of this object
888        long numChildren  = ref.children_size();
889 
890        if (( numChildren > 0 ) && (ref.getRetainedSize() == 0)) {
891          int start        = ref.getVisitedCount();
892          int i = 0;
893          long  allChildren[] = ref.children();
894 
895          if ( MadmapMain.runDump() ) {
896            System.out.println( "scanned " + (markedInThisPass++) + " curr:" + ref.className() + "@" + 
897              Long.toHexString( ref.addr() ) + " already visited " + start + " children of " + numChildren);
898          }
899          
900          if ( start < numChildren ) {
901            boolean pushedRef = false;
902            for ( i = ((int)numChildren - start); i > 0; i-- ) {
903              // If the child is not visited yet, push it
904              // in case of a cycle, the parent will already be visited
905              HprofHeapCollectable childRef = getRefFromAddr( allChildren[i - 1] );
906              
907              // 080828 - handle null child ref appearing in input file (should be rare)
908              if ( (childRef != null) && (! childRef.isAlive())) {
909                if ( pushedRef == false) {
910                  _addr_stack.push( ref );
911                  pushedRef = true;
912                  if ( MadmapMain.runDump() ) {
913                    System.out.println( " ref: " + ref.className() + "@" + Long.toHexString( ref.addr() ));
914                  }
915                }
916                
917                _addr_stack.push( childRef );
918                ref.visited( childRef );
919                
920                if ( MadmapMain.runDump() ) {
921                  System.out.println( "pushing ref: " + ref.className() + "@" + Long.toHexString( ref.addr() ) + "->" + 
922                    Long.toHexString( childRef.addr() ));
923                }              
924              } else {
925                if ( MadmapMain.runDump() ) {
926                  System.out.println( "child already live: ref: " + ref.className() + "@" + Long.toHexString( ref.addr() ) + "->" + 
927                    Long.toHexString( childRef.addr() ));
928                }
929              }
930            }
931            
932            // When we get here all children are alive, they are all visited, but not necessarily visited by this parent
933            // add the children we actually visited
934            if ( pushedRef == false ) {
935            
936              if ( MadmapMain.runDump() ) {
937                System.out.println( "ref: " + ref.className() + "@" + Long.toHexString( ref.addr() ) + ": all children are visited" ); 
938              }
939              
940              if (ref.getRetainedSize() == 0 ) {
941                // if we get here all the children are visited from ref, it is a very simple graph with no cycles
942                ref.setRetainedSize( ref.size() );
943                accumulateChildrenSize( ref );
944              }
945            }
946          } else {
947            assert (ref.getRetainedSize() == 0) : "resetting retained size?";
948            
949            if ( (start == numChildren) && ( ref.getRetainedSize() == 0 ) ) {
950              // if we get here all the children are visited from ref, it is a very simple graph with no cycles
951              ref.setRetainedSize( ref.size() );
952              accumulateChildrenSize( ref );
953            } else {
954              //if ( verbose() ) {
955              //  System.out.println( "visited stack is empty: " + ref.className() + "@" + Long.toHexString( ref.addr() ) );
956              //}
957            }
958          }
959        } else {
960          if ( ref.getRetainedSize() == 0 ) {
961            // This object has no children
962            ref.setRetainedSize( ref.size() );
963          } else {
964            // If we get here, this object has already been fully accounted for by earlier work, nothing to do
965          }
966          //assert ref.getRetainedSize() < _liveObjectsSize : "ret size > total live size!";
967        }
968      } else {
969        _logger.myLog( getWindow(),  "markChildren: ====================================================================================" );
970        _logger.myLog( getWindow(),  "markChildren: pushed null descending from root " + Long.toHexString(ho.addr()) + " in heap table!!" );
971        _logger.myLog( getWindow(),  ho.toString() );
972        _logger.myLog( getWindow(),  "markChildren: ====================================================================================" );
973      }
974    }
975    
976    assert _addr_stack.empty() : "exiting markChildren but _marking_stack is not empty! " ;
977  }
978 
979  public void iterativeCollectChildrenSizeOld( HprofHeapCollectable ho ) {
980    int markedInThisPass  = 0;
981    java.util.Stack _addr_stack        = new java.util.Stack();
982 
983    if ( MadmapMain.runDump() ) {
984      System.out.println( "Marking root: " + ho.className() + "@" + Long.toHexString( ho.addr() ) );
985    }
986 
987    _addr_stack.push( ho );
988    
989    // In a loop, keep marking and adding children going down from this root
990    while ( ! _addr_stack.empty() ) {
991      
992      // Get the long that is a heap ref
993      HprofHeapCollectable  ref   = (HprofHeapCollectable)_addr_stack.pop();
994      
995      if ( ref != null ) {
996        ref.setLiveness( true );        
997        
998        // Add the children of this object
999        long numChildren  = ref.children_size();
1000        int start        = ref.getVisitedCount();
1001 
1002        if ( MadmapMain.runDump() ) {
1003          System.out.println( "scanned " + (markedInThisPass++) + " curr:" + ref.className() + "@" + 
1004            Long.toHexString( ref.addr() ) + " already visited children " + start + " of " + numChildren);
1005        }
1006 
1007        if ( numChildren > 0 ) {
1008          int i = 0;
1009          for ( i = start; i < numChildren; i++ ) {
1010            // If the child is not visited yet, push it
1011            // in case of a cycle, the parent will already be visited
1012            HprofHeapCollectable childRef = getRefFromAddr( ref.children()[i] );
1013            if ( ! childRef.isAlive() ) {
1014              // add the parent so we can continue to visit the other children
1015              _addr_stack.push( ref );
1016              _addr_stack.push( childRef );
1017              ref.visited( childRef );
1018              
1019              if ( MadmapMain.runDump() ) {
1020                System.out.println( " ref: " + ref.className() + "@" + Long.toHexString( ref.addr() ) + "->" + 
1021                  Long.toHexString( childRef.addr() ));
1022              }              
1023              break;
1024            } else {
1025              if ( MadmapMain.runDump() ) {
1026                System.out.println( "child already live: ref: " + ref.className() + "@" + Long.toHexString( ref.addr() ) + "->" + 
1027                Long.toHexString( childRef.addr() ));
1028              }
1029            }           
1030          } 
1031          
1032          // if we get here all the children are visited
1033          if ( i == numChildren ) {
1034            if ( ref.getRetainedSize() == 0 ) {
1035              ref.setRetainedSize( ref.size() );
1036            }
1037            // Collect the visited children sizes into ref
1038            Stack visited = ref.getVisitedStack();
1039            if ( visited != null ) {
1040              while ( ! visited.empty() ) {
1041                HprofHeapCollectable childRef = (HprofHeapCollectable) visited.pop();
1042                long childSize = childRef.getRetainedSize();
1043                ref.setRetainedSize( ref.getRetainedSize() + childSize);
1044                if ( MadmapMain.runDump() ) {
1045                  System.out.println( "added " + childRef.className() + "@" + Long.toHexString( childRef.addr() ) + "=" + childSize +
1046                    " to:" + ref.className() + "@" + Long.toHexString( ref.addr() ) + " total size:" + ref.getRetainedSize() );
1047                }
1048              }
1049              
1050              if ( MadmapMain.runDump() ) {
1051                System.out.println( "Completed retained size collection " + ref.className() + "@" + 
1052                    Long.toHexString( ref.addr() ) + " total size:" + ref.getRetainedSize()  );
1053              }
1054              
1055            } else {
1056              if ( MadmapMain.runDump() ) {
1057                System.out.println( "visited stack is empty: " + ref.className() + "@" + Long.toHexString( ref.addr() ) );
1058              }
1059            }
1060          }
1061        } else {
1062          // This object has no children
1063          ref.setRetainedSize( ref.size() );
1064          //if ( MadmapMain.runDump() ) {
1065          //  System.out.println( "no children: " + ref.className() + "@" + Long.toHexString( ref.addr() ) );
1066          //}
1067        }
1068      } else {
1069        _logger.myLog( getWindow(),  "markChildren: ====================================================================================" );
1070        _logger.myLog( getWindow(),  "markChildren: pushed null descending from root " + Long.toHexString(ho.addr()) + " in heap table!!" );
1071        _logger.myLog( getWindow(),  ho.toString() );        
1072        _logger.myLog( getWindow(),  "markChildren: ====================================================================================" );
1073      }
1074    }
1075    
1076    assert _addr_stack.empty() : "exiting markChildren but _marking_stack is not empty! " ;
1077  }
1078 
1079 
1080  void iterativeSortOnRetainedSize( Vector rootSet, String description) {
1081    JProgressBar  progress_bar   = null;
1082    int i = 0;
1083    Iterator<HprofRoot> irs = rootSet.iterator();
1084 
1085    _logger.myLog( getWindow(),  elapsedTime() + ": analyze: iterative retained size by: " + description );
1086    
1087    if ( ! MadmapMain.noGUI() ) {
1088      progress_bar = getWindow().getProgressBar();
1089      getWindow().getLabelForProgressBar().setText("Retained Size: " + description);
1090      progress_bar.setMinimum(0);
1091      progress_bar.setMaximum(rootSet.size() - 1);
1092      progress_bar.setValue(0);
1093    }
1094 
1095    try {
1096      while( irs.hasNext() ) {
1097        HprofRoot             hr  = irs.next();
1098        HprofHeapCollectable  ho;
1099          
1100        assert hr != null : "root should not be null";  
1101          
1102        ho = (HprofHeapCollectable) this.getClasses().get( new HprofHeapElement(hr.addr()) );
1103        if ( ho == null ) {
1104          ho = (HprofHeapCollectable) this.getObjects().get( new HprofHeapElement( hr.addr()) );
1105        }
1106        
1107        if ( ho != null ) {
1108          if ( MadmapMain.testFeature() == true ) {
1109            iterativeCollectChildrenSizeOld( ho );
1110          } else {
1111            iterativeCollectChildrenSize( ho );
1112          }
1113        } else {
1114          // The 0 root is the primordial root
1115          if (hr.addr() != 0 && MadmapMain.verbose() && hr.rootType().equals("<system class>")) {
1116            _logger.myLog( getWindow(),  "Cannot find system class root[" + Long.toHexString(hr.addr()) + "] in heap table or in class list!!" );
1117            _logger.myLog( getWindow(),  hr.toString() );            
1118          }
1119        }
1120 
1121        if( ( ! MadmapMain.noGUI() ) && (i++ % 100 == 0)) {
1122          progress_bar.setValue(i);
1123          getWindow().updateMemoryProgressBar();          
1124        }
1125      }
1126 
1127      if( ! MadmapMain.noGUI() ) {
1128        progress_bar.setValue(progress_bar.getMaximum());
1129      }
1130      _logger.myLog( getWindow(),  elapsedTime() + ": analyze: iterative retained size complete" );      
1131    } catch( Throwable e ) {
1132      _logger.myLog( getWindow(),  elapsedTime() + ": iterative retained size: " + e );
1133      e.printStackTrace();
1134    }
1135  }
1136 
1137  public void displayRetainedSortResults(String description) {
1138    // Object retained size tab first  
1139    {
1140      ArrayList<HprofHeapAllocation> objList  = new java.util.ArrayList<HprofHeapAllocation>();
1141        // make a list for the table model
1142      ArrayList<HprofHeapAllocation> retModel   = new ArrayList<HprofHeapAllocation>();    
1143    
1144      // Add objects which retain > 10% of live size
1145      for (Enumeration e = this.getObjects().keys() ; e.hasMoreElements() ; ) {
1146        Object k = e.nextElement();
1147        HprofHeapAllocation ho = this.getObjects().get( k );
1148        long  rs                = ho.getRetainedSize();        
1149        float pctLiveSize       = ((float) rs / (float) _liveObjectsSize)  *  (float)100.0;
1150        
1151        if ( pctLiveSize > 10.0 ) {
1152          objList.add( ho );
1153        }
1154      }
1155      Collections.sort(objList, new RetainedSizeComparator());
1156 
1157      _logger.myLog( getWindow(),  "Live objects sorted by cumulative retained size by: " + description );
1158      _logger.myLog( getWindow(),  " " );
1159      _logger.myLog( getWindow(),  "Retained Size\tPct of Live Size\tClass@ObjAddr" );
1160      _logger.myLog( getWindow(),  "==================================================================================================== " );
1161 
1162      Iterator<HprofHeapAllocation>   ihoc3 = objList.iterator();
1163      while( ihoc3.hasNext() ) {
1164        HprofHeapAllocation hk  = ihoc3.next();
1165        long  rs                = hk.getRetainedSize();        
1166        float pctLiveSize       = ((float) rs / (float) _liveObjectsSize)  *  (float)100.0;
1167        boolean haveThread      = false;
1168        HprofThreadData thd     = null;
1169        
1170        // Print the thread name as a convenience to the user, it is in the thread record
1171        if ( hk.className().equals("java.lang.Thread") ) {
1172          thd = (HprofThreadData) getThreads().get( (int) hk.addr() );
1173          if ( thd != null ) {
1174            haveThread = true;
1175          }
1176        }
1177 
1178        {
1179          // Add this object's ret size to its class' ret size
1180          HprofClassElement thisClass = (HprofClassElement) hk.getActualClass();
1181          thisClass.setTotalRetainedSize( thisClass.getTotalRetainedSize() + hk.getRetainedSize() );
1182        }
1183 
1184        //if ( pctLiveSize > 10.0 ) {
1185        {
1186          int stackId = hk.getStackTrace();
1187          HprofStackTraceData std = null;
1188          if ( stackId != 0 ) {
1189            std = (HprofStackTraceData)getStackTraces().get(stackId);
1190          }
1191          List stkTrc = null;
1192          if ( std != null ) { 
1193            stkTrc = std.getStackVector();
1194          }
1195 
1196          // Things with no stack trace are unlikely to be a leak
1197          if ( (stkTrc != null) && (stkTrc.size() == 1) && ((String)stkTrc.get(0)).equals("<empty>") ) {
1198            // really need to do this?
1199            //ihoc3.remove();
1200          } else {        
1201            // now examine children and get their retained size
1202            // Leak guesses will be based on the idea of "if obj x retains n%, x is a 
1203            // leak guess if no child of x retains more than (n - 5)%
1204            long[] child_refs = hk.children();
1205            boolean notLeak = false;
1206            if ( child_refs != null ) {
1207              for ( int i = 0; i < child_refs.length; i++ ) {
1208                HprofHeapCollectable child = getRefFromAddr( child_refs[i] );
1209                if (child != null) {
1210                  long  rsc               = child.getRetainedSize();
1211                  float childPctLiveSize  = ((float) rsc / (float) _liveObjectsSize)  *  (float)100.0;
1212                  if ( childPctLiveSize > (pctLiveSize - (float)5.0) ) {
1213                    notLeak = true;       
1214                  }
1215                } else {
1216                  notLeak = true;       
1217                }
1218              }
1219              if (! notLeak ) {
1220                getGuesses().put( hk.addr(), (new Boolean(true)) );
1221              }
1222            }
1223            StringBuffer  objDetail = new StringBuffer(rs + "\t" + pctLiveSize + "%\t" + "\t" + hk.className() + "@" + Long.toHexString( hk.addr()));
1224            if ( haveThread == true ) {
1225              objDetail.append(" [ " + thd.name() + " ]");
1226            }
1227            if (! notLeak ) {
1228              objDetail.append("\t *** Leak Guess ***");              
1229            }
1230            _logger.myLog( getWindow(), objDetail.toString() );
1231 
1232            if (stkTrc != null) {
1233              for (int j = 0; j < stkTrc.size(); j++ ) {
1234                String s = (String) stkTrc.get( j );
1235                _logger.myLog( getWindow(), "  " + s );
1236              }
1237            }
1238            retModel.add( hk );          
1239          }
1240        } 
1241      }
1242      
1243      if ( ! MadmapMain.noGUI() ) {
1244        getWindow().addRetainedHeapTab( this, retModel, _liveObjectsSize, description );
1245      }
1246    }
1247 
1248    _logger.myLog( getWindow(),  "==================================================================================================== " );
1249  }
1250  
1251  
1252  public void doRetainedByClass() {
1253    for (int i = 0; i < _rootDescNames.length; i++) {
1254      int verifyRoots = getRoots().size();
1255      _logger.myLog( getWindow(),  "==================================================================================================== " );
1256      Collections.sort(getRoots(), new RootComparator(_rootHprofNames[i]));
1257      assert verifyRoots == getRoots().size() : "roots sort is messed up";
1258 
1259      String description = _rootHprofNames[i];
1260  
1261      // Now build a list of retained-by-class to get ready to show in a tab
1262      {
1263        ArrayList<HprofHeapCollectable> classList  = new java.util.ArrayList<HprofHeapCollectable>();    
1264        
1265        // Add classes which retain > 10% of live size
1266        for (Enumeration e = this.getClasses().keys() ; e.hasMoreElements() ; ) {
1267          Object k = e.nextElement();
1268          HprofHeapCollectable ho = (HprofHeapCollectable) this.getClasses().get( k );
1269          long  rs                = ho.getRetainedSize();        
1270          float pctLiveSize       = ((float) rs / (float) _liveObjectsSize)  *  (float)100.0;
1271          
1272          if ( pctLiveSize > 10.0 ) {
1273            classList.add( ho );
1274          }
1275        }
1276        
1277        Collections.sort(classList, new CumulativeRetainedSizeComparator());
1278        // make a list for the table model
1279        ArrayList<HprofHeapCollectable> classRetModel   = new ArrayList<HprofHeapCollectable>();    
1280 
1281        _logger.myLog( getWindow(),  "Classes sorted by cumulative retained size by: " + description );
1282        _logger.myLog( getWindow(),  " " );
1283        _logger.myLog( getWindow(),  "Retained Size\tPct of Live Size\tInstance Count\tClassName@ClassAddr" );
1284        _logger.myLog( getWindow(),  "==================================================================================================== " );
1285        
1286        Iterator<HprofHeapCollectable>   ihoc = classList.iterator();
1287        while( ihoc.hasNext() ) {
1288          HprofHeapCollectable hk  = ihoc.next();
1289          classRetModel.add( hk );          
1290        }
1291 
1292        if ( ! MadmapMain.noGUI() ) {
1293          getWindow().addRetainedByClassTab( this, classRetModel, _liveObjectsSize, description );
1294        }
1295      }    
1296    }
1297  }
1298  
1299  
1300  // These two string arrays should be kept in sync
1301  String[] _rootDescNames = {
1302    "Classes",
1303    "Threads",
1304    "Java stack",
1305    "JNI global refs"
1306  };
1307  
1308  String[] _rootHprofNames = {
1309    "<system class>",
1310    "<thread>",
1311    "<Java stack>",
1312    "<JNI global ref>"
1313  };
1314  
1315  /**
1316  * Search the class list and record the basic type array
1317  * classes, they will be installed into basic type array
1318  * objects in a later step
1319  */
1320  void reconcileBasicTypeArrays() {  
1321    Collection<HprofClassElement> hoc = this.getClasses().values();
1322    Iterator<HprofClassElement>   ihoc = hoc.iterator();
1323    
1324    while( ihoc.hasNext() ) {
1325      HprofClassElement hc = ihoc.next();
1326      String  nm = hc.className();
1327      
1328      if (( nm == "boolean[]" ) || (nm == "[Z")) {
1329        boolArrayKlass = hc;
1330      } else if (( nm == "byte[]" ) || (nm == "[B")) {
1331        byteArrayKlass = hc;
1332      } else if (( nm == "char[]" ) || (nm == "[C")) {
1333        charArrayKlass = hc;
1334      } else if (( nm == "short[]" ) || (nm == "[S")) {
1335        shortArrayKlass = hc;
1336      } else if (( nm == "int[]" ) || (nm == "[I")) {
1337        intArrayKlass = hc;
1338      } else if (( nm == "long[]" ) || (nm == "[J")) {
1339        longArrayKlass = hc;
1340      } else if (( nm == "float[]" ) || (nm == "[F")) {
1341        floatArrayKlass = hc;
1342      } else if (( nm == "double[]" ) || (nm == "[D")) {
1343        doubleArrayKlass = hc;
1344      }
1345    }
1346  }
1347  
1348 
1349  public void analyze() {
1350    if ( MadmapMain.verbose() ) {
1351      _logger.myLog( getWindow(),  elapsedTime() + ": analyze: _roots_list.size() = " + this.getRoots().size() );
1352    }
1353 
1354    reconcileBasicTypeArrays();
1355    
1356    if (isBinary() && (MadmapMain.printFinalizers() == true)) {
1357      printFinalizers();
1358    }
1359 
1360    iterativeMarking();
1361 
1362    if ( MadmapMain.verbose() ) {
1363      _logger.myLog( getWindow(),  elapsedTime() + ": analyze: build live table " );
1364    }      
1365 
1366    long build_startTime = System.currentTimeMillis();
1367    buildLiveObjectsTable();
1368    long build_endTime = System.currentTimeMillis();
1369    if ( MadmapMain.verbose() ) {
1370      System.out.println( "Built live graph in " + (build_endTime - build_startTime) + "ms");
1371    }
1372        
1373    if ( MadmapMain.verbose() ) {
1374      _logger.myLog( getWindow(),  " " );
1375      _logger.myLog( getWindow(),  elapsedTime() + ": analyze: build live table complete " );
1376      _logger.myLog( getWindow(),  " " );
1377    }      
1378 
1379    if ( MadmapMain.runSystemGC() ) {
1380      _logger.myLog( getWindow(),  elapsedTime() + ": analyze: System.gc() for footprint analysis " );
1381      System.gc();
1382      _logger.myLog( getWindow(),  elapsedTime() + ": analyze: System.gc() done " );
1383    }
1384    
1385    _logger.myLog( getWindow(),  " " );
1386    _logger.myLog( getWindow(),  "Total number of types: " + ( this.getClasses().size() ));
1387    
1388        
1389    buildLiveObjectsHistogram();
1390    if ( !isBinary() && (MadmapMain.printFinalizers() == true)) {
1391      printFinalizers();
1392    }
1393 
1394    {
1395      // retained size code starts here 080524      
1396      resetForScanning();
1397      
1398      int verifyRoots = getRoots().size();
1399      
1400      for (int i = 0; i < _rootDescNames.length; i++) {
1401        _logger.myLog( getWindow(),  "==================================================================================================== " );
1402        Collections.sort(getRoots(), new RootComparator(_rootHprofNames[i]));
1403        assert verifyRoots == getRoots().size() : "roots sort is messed up";
1404        if ( MadmapMain.runRecursiveChildrenSize() == true ) {
1405          sortOnRetainedSize( getRoots(), _rootDescNames[i] );
1406        } else {
1407          iterativeSortOnRetainedSize( getRoots(), _rootDescNames[i] );
1408        }
1409        displayRetainedSortResults( _rootDescNames[i] );
1410        resetForScanning();
1411      }
1412    }
1413    _logger.myLog( getWindow(),  elapsedTime() + ": Analysis complete." );    
1414 
1415  }
1416 
1417  public MainWindow getWindow() { return _window; }
1418 
1419  public Madmap( String name, MainWindow theWindow ) {
1420    _window = theWindow;
1421    preinit( name );    
1422  }
1423 
1424  public Madmap( File inputFile, MainWindow theWindow ) {
1425    String name;
1426    _window = theWindow;
1427    try {
1428        name = inputFile.getCanonicalPath();      
1429    } catch (IOException e) {
1430      System.out.println("Something wrong with file from gui");
1431      e.printStackTrace();
1432      return;
1433    }
1434    preinit( name );    
1435  }
1436 
1437  public Madmap( String name ) {
1438    preinit( name );
1439  }
1440 
1441  public static boolean isBinaryDump(String name) {
1442    FileInputStream   fis = null;
1443    DataInputStream   dis;
1444    BufferedInputStream   bis;
1445    byte[] rawBytes  = new byte[ 18 ];
1446    byte b = -1;
1447 
1448          try {    
1449                  fis = new FileInputStream( name );
1450      bis = new BufferedInputStream( fis );
1451      dis = new DataInputStream( bis );
1452    
1453      // File starts with null-terminated "JAVA PROFILE 1.0.1"
1454      int bytesRead     = dis.read( rawBytes );
1455      b = dis.readByte();
1456      dis.close();
1457    } catch (IOException e) {
1458      System. out. println ( " Exception while examining file type: " + e );
1459      e.printStackTrace();
1460      System.exit(0);
1461    }
1462     
1463    String header = new String( rawBytes );
1464    if ((header.equals ( "JAVA PROFILE 1.0.1" ) || 
1465        header.equals ( "JAVA PROFILE 1.0.2" )) && (b == 0)) {
1466      return true;
1467    }
1468    return false;
1469 
1470  }
1471      
1472  private void preinit( String name ) {
1473    if (MadmapMain.verbose()) {
1474      System.out.println( "Opening file: " + name );    
1475    }
1476    _fileName = name;
1477    _isBinary = Madmap.isBinaryDump( _fileName );
1478 
1479    // binary dumps dont need the workaround below
1480    if (_isBinary) {
1481      return;
1482    } 
1483 
1484          // 070307 - JDK 1.4 does not emit class
1485          // entries for basic type arrays, so I create a phony placeholder entry 
1486          // to use when building up the instance size/count info
1487          if ( MadmapMain.jdk14_compatible() ) {
1488                  boolArrayKlass    = new HprofClassElement( (long) 999, "bool[]" );
1489                  byteArrayKlass    = new HprofClassElement( (long) 998, "byte[]" );
1490                  charArrayKlass    = new HprofClassElement( (long) 997, "char[]" );
1491                  shortArrayKlass   = new HprofClassElement( (long) 996, "short[]" );
1492                  intArrayKlass     = new HprofClassElement( (long) 995, "int[]" );
1493                  longArrayKlass    = new HprofClassElement( (long) 994, "long[]" );
1494                  floatArrayKlass   = new HprofClassElement( (long) 993, "float[]" );
1495                  doubleArrayKlass  = new HprofClassElement( (long) 992, "double[]" );
1496 
1497                  _class_list.put( boolArrayKlass, boolArrayKlass );
1498                  _class_list.put( byteArrayKlass, byteArrayKlass );
1499                  _class_list.put( charArrayKlass, charArrayKlass );
1500                  _class_list.put( shortArrayKlass, shortArrayKlass );
1501                  _class_list.put( intArrayKlass, intArrayKlass );
1502                  _class_list.put( longArrayKlass, longArrayKlass );
1503                  _class_list.put( floatArrayKlass, floatArrayKlass );
1504                  _class_list.put( doubleArrayKlass, doubleArrayKlass );
1505          }
1506  }
1507}

[all classes][net.sf.madmap]
EMMA 2.0.5312 (C) Vladimir Roubtsov