View Javadoc

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   */
14   package net.sf.madmap;
15  
16  import java.io.*;
17  import java.util.*;
18  import java.util.concurrent.*;
19  import java.util.concurrent.atomic.AtomicInteger;
20  import java.math.*;
21  import java.lang.management.*; 
22  import javax.management.*;
23  import javax.swing.JOptionPane;
24  
25  /**
26   * 
27   * HprofReader manages reading the hprof file using a thread pool of Workers.
28   * 
29   * @author ecaspole
30   */
31  public class HprofReader implements IHprofReader, HprofReaderMBean {
32  
33    ILogger	_logger;
34  
35    static String  objStart = new String( "O" );
36    static String  arrStart = new String( "A" );
37    static String  clsStart = new String( "CL" );
38  
39    // MBean fields and methods
40    AtomicInteger     _objects  = new AtomicInteger(0);
41    AtomicInteger     _arrays   = new AtomicInteger(0);
42    AtomicInteger     _classes  = new AtomicInteger(0);  
43    public int getCurrentObjects()      { return _objects.get(); }
44    public int getCurrentArrays()       { return _arrays.get(); }
45    public int getCurrentClasses()      { return _classes.get(); }
46    public String getReaderName()       { return "HprofReader:workers=" + MadmapMain.concurrency(); }
47  
48    public HprofReader() { }
49    
50    public void setLogger( ILogger logger ) { _logger = logger; }
51    
52    public static FileInputStream openHprofFile(String fileName)
53    {
54  	  FileInputStream	  fis;
55  
56  	  try {    
57  		  fis = new FileInputStream( fileName );
58  		  return fis;
59  	  } catch ( Exception ie ) {
60  		  System. out. println ( "Error opening file : Caught " + ie );
61  		  ie.printStackTrace();
62  	  }
63  	  return null;
64    }
65  
66    public void parse( Madmap owner, String fileName) {
67  	  long fileSize = 0;
68  
69  	  try {    
70  		  File  fi = new File( fileName );
71  		  fileSize = fi.length();
72  		  if ( MadmapMain.verbose() ) {
73  			  _logger.myLog( owner.getWindow(), "Total file length of " + fileName + " is " + fileSize );
74  		  }
75  	  } catch ( Exception ie ) {
76  		  System. out. println ( "Error opening file : Caught " + ie );
77  		  ie.printStackTrace();
78  	  }
79  
80  	  long  stripeWidth = fileSize / MadmapMain.concurrency();
81  	  if ( MadmapMain.verbose() ) {
82  		  _logger.myLog( owner.getWindow(), "Stripe width is " + stripeWidth );
83  		  _logger.myLog( owner.getWindow(), "Going to run with " + MadmapMain.concurrency() + ( MadmapMain.concurrency() == 1 ? " thread" : " threads" ));
84  	  }
85  
86  	  try {
87  		  ExecutorService tpe = Executors.newFixedThreadPool( MadmapMain.concurrency() );
88  		  for ( int i = 0; i < MadmapMain.concurrency(); i ++ ) {
89  			  tpe.execute( new Worker( owner, i, openHprofFile(fileName), i * stripeWidth, stripeWidth ) );
90  		  }
91  		  // Shutdown input on the thread queue and wait for the jobs to complete
92  		  tpe.shutdown();
93  		  tpe.awaitTermination(9999, TimeUnit.SECONDS); 
94  	  } catch ( InterruptedException ie ) {
95  		  System. out. println ( "*** InterruptedException happened 2" );
96  	  }
97    }
98  
99    /**
100    * Workers read the hprof file in 1 or more chunks based on the available 
101    * concurrency.
102    * 
103    *  @author ecaspole
104    */
105 	private class Worker implements Runnable {
106 
107   Madmap       _owner              = null;
108   
109   ConcurrentHashMap<HprofHeapAllocation,HprofHeapAllocation>       _heap_objects_table = null;
110   ConcurrentHashMap       _stack_trace_table  = null;
111   ConcurrentHashMap       _threads_list       = null;
112   Vector          _roots_list         = null;
113   ConcurrentHashMap       _class_list         = null;
114 
115   boolean         _verbose            = false;
116 
117   public void dumpObjectsTable()    { _heap_objects_table = null; }
118 
119   public ConcurrentHashMap getStackTraces()    { return _stack_trace_table; }
120   public ConcurrentHashMap getThreads()        { return _threads_list; }
121   public Vector getRoots()       { return _roots_list; }
122   public ConcurrentHashMap getClasses()       { return _class_list; }
123 		
124   FileInputStream	  _fis;
125   LineNumberReader  _bfr;
126   int               _readerId;
127   long              _startOffset;
128   long              _estimatedCompletionLine;
129   
130   String          _pushed_string      = null;
131   int             _linesSeen          = 0;
132   long            _startTime          = 0;
133    
134   org.apache.regexp.RE	thread_start_re = new org.apache.regexp.RE( "THREAD START .*" );
135   org.apache.regexp.RE	thread_end_re   = new org.apache.regexp.RE( "THREAD END .*" );
136   org.apache.regexp.RE	stack_trace_re  = new org.apache.regexp.RE( "^TRACE ([0-9]*):" );
137   org.apache.regexp.RE	obj_start_re    = new org.apache.regexp.RE( "^OBJ .*" );
138   org.apache.regexp.RE	array_start_re  = new org.apache.regexp.RE( "^ARR .*" );
139 
140   org.apache.regexp.RE	thread_start_obj   = new org.apache.regexp.RE( "obj=([0-9A-Za-z]*),.*" );
141   org.apache.regexp.RE	thread_start_id    = new org.apache.regexp.RE( "id = ([0-9 ]*),.*" );
142   org.apache.regexp.RE	thread_start_name  = new org.apache.regexp.RE( "name=(.*),.*" );
143   org.apache.regexp.RE	thread_start_group = new org.apache.regexp.RE( "group=(\".*\")" );
144 
145   org.apache.regexp.RE	_stack_trace_title_re  = new org.apache.regexp.RE( "^TRACE ([0-9]*):" );
146   org.apache.regexp.RE	_stack_trace_item_re  = new org.apache.regexp.RE( "\t(.*)" );
147 
148   org.apache.regexp.RE	_heap_dump_begin_re   = new org.apache.regexp.RE( "^HEAP DUMP BEGIN " );
149   org.apache.regexp.RE	_heap_dump_objects_re = new org.apache.regexp.RE( "([0-9]*) objects, " );
150   org.apache.regexp.RE	_heap_dump_bytes_re   = new org.apache.regexp.RE( ", ([0-9]*) bytes" );
151   org.apache.regexp.RE	_heap_dump_end_re     = new org.apache.regexp.RE( "^HEAP DUMP END" );
152 
153   org.apache.regexp.RE	_root_begin_re   = new org.apache.regexp.RE( "^ROOT ([0-9A-Za-z]*) " );
154   org.apache.regexp.RE	_root_kind_re    = new org.apache.regexp.RE( "kind=([0-9A-Za-z -<>]*), " );
155   org.apache.regexp.RE	_root_kind_unknown_re  = new org.apache.regexp.RE( "kind=<unknown>" );
156   org.apache.regexp.RE	_root_kind_busymon_re  = new org.apache.regexp.RE( "kind=<busy monitor>" );
157   org.apache.regexp.RE	_root_classname_re      = new org.apache.regexp.RE( " name=([0-9A-Za-z.$]*)" );
158   org.apache.regexp.RE	_root_id_re      = new org.apache.regexp.RE( "id=(.*), " );
159   org.apache.regexp.RE	_root_trace_re   = new org.apache.regexp.RE( "trace= ([0-9]*)" );
160   
161   org.apache.regexp.RE	_obj_all_re      = new org.apache.regexp.RE( "^OBJ ([0-9A-Za-z]*) [:punct:]sz=([0-9]*), trace=([0-9]*), class=([0-9A-Za-z_.$]*)@([0-9a-f]*)" );
162   org.apache.regexp.RE	_obj_member_both_re  = new org.apache.regexp.RE( "^\t([0-9A-Za-z_$]*)[ \t]+([0-9A-Za-z_]*)" );
163 
164   // This one for class types
165   org.apache.regexp.RE	_arr_type_both_re   = new org.apache.regexp.RE( "elem type=(.*)@([0-9A-Za-z]*)" );
166 
167   // This one for basic type arrays
168   org.apache.regexp.RE	_arr_type_re2   = new org.apache.regexp.RE( "elem type=(.*)[:punct:]" );
169 
170   org.apache.regexp.RE	_arr_elem_both_re  = new org.apache.regexp.RE( "^\t([:punct:][0-9]+[:punct:])[\t ]+([0-9A-Za-z]+)" );
171 
172   //org.apache.regexp.RE	_arr_data_re    = new org.apache.regexp.RE( "sz=([0-9]*), trace=([0-9]*), nelems=([0-9A-Za-z]*), " );
173   org.apache.regexp.RE	_arr_all_re   = new org.apache.regexp.RE( "^ARR ([0-9A-Za-z]*) [:punct:]sz=([0-9]*), trace=([0-9]*), nelems=([0-9A-Za-z]*), " );
174 
175   org.apache.regexp.RE	_cls_super_re   = new org.apache.regexp.RE( "^\tsuper[ \t]+([0-9A-Za-z]*)" );
176   org.apache.regexp.RE	_cls_loader_re  = new org.apache.regexp.RE( "^\tloader[ \t]+([0-9A-Za-z]*)" );
177   org.apache.regexp.RE	_cls_static_name_re   = new org.apache.regexp.RE( "^\tstatic ([0-9_A-Za-z.$]*)" );
178   org.apache.regexp.RE	_cls_static_addr_re   = new org.apache.regexp.RE( "^\tstatic [0-9_A-Za-z.$]+[\t]+([0-9a-f]*)" );
179   //org.apache.regexp.RE	_cls_data_re    = new org.apache.regexp.RE( "name=(.*), trace=([0-9]*)" );
180   org.apache.regexp.RE	_cls_all_re     = new org.apache.regexp.RE( "^CLS ([0-9A-Za-z]*) [:punct:]name=(.*), trace=([0-9]*)" );
181 		
182 		
183 		public  void run() {
184 			
185     int   ln = 0;
186     
187     _startTime = System.currentTimeMillis();
188     System. out. println ( "Moving to start position " + _startOffset );
189 
190     try {
191       InputStreamReader isr;
192       _fis.skip( _startOffset );
193       
194       isr = new InputStreamReader( _fis );
195       _bfr = new LineNumberReader( isr );
196 
197     } catch ( IOException ioe ) {
198       System. out. println ( "Exception while seeking to file start position..." );
199       ioe.printStackTrace();
200     }
201 
202     System. out. println ( "Loading file from start position " + _startOffset );
203 
204     readAndProcessLines(-1);
205     long endMillis = System.currentTimeMillis();
206 
207     System. out. println ( "Done Loading stripe from start position: " + _startOffset );
208     System. out. println ( "Elapsed time: " + elapsedTime());    
209   }
210   
211   /**
212  * @param owner		the Madmap document this Worker is working for
213  * @param id		the id of this Worker
214  * @param rdr		the FileInputStream to read from
215  * @param startPos	the position to start from as computed by the HprofReader
216  * @param stripeWidth	the number of bytes to be read, it is only used for 
217  * 						progress messages.
218  */
219 public Worker(Madmap owner, int id, FileInputStream rdr, long startPos, long stripeWidth) {
220     _startOffset  = startPos;
221     _fis          = rdr;
222     _owner        = owner;
223     _readerId     = id;
224     
225     // about 35 chars/line on average...
226     _estimatedCompletionLine = stripeWidth / 35;
227     if (( ! MadmapMain.noGUI()) && ( _readerId == 0 )) {
228       _owner.getWindow().getProgressBar().setMaximum((int)_estimatedCompletionLine);
229       _owner.getWindow().getLabelForProgressBar().setText("Loading File");
230     }
231     System. out. println ( "HprofReader reader id = " + _readerId + "  _estimatedCompletionLine " + _estimatedCompletionLine );
232 
233     _heap_objects_table = owner.getObjects();
234     _stack_trace_table  = owner.getStackTraces();
235     _threads_list       = owner.getThreads();
236     _roots_list         = owner.getRoots();
237     _class_list         = owner.getClasses();
238   }
239 
240   long[]  longArrayListtoLongArray( ArrayList in ) {
241     long[]  out = new long[ in.size() ];
242     for ( int i = 0; i < out.length; i++ ) {
243       out[ i ] = ((Long) in.get( i )).longValue();
244     }
245     return out;
246   }
247 
248 
249   public String matchAndGet( org.apache.regexp.RE active, String s) {
250     if ( active.match(s) == true ) {
251       return active.getParen( 1 );
252     } else {
253       return null;
254     }
255   }
256 
257   public long convertAddrStringToLong( String s) {
258     return (new BigInteger( s, 16 )).longValue();
259   }
260 
261   public void handleClass( String s ) {
262     String objstr   = null;
263     String trcstr   = null;
264     String clsstr  = null;
265     String elem_name = null;
266     String elem_addr = null;
267     String sooper   = null;
268     String loader   = null;
269     String next     = null;
270     ArrayList st_names = new ArrayList();
271     ArrayList st_refs  = new ArrayList();
272 
273     if ( _cls_all_re.match( s ) ) {
274       objstr   = _cls_all_re.getParen( 1 );
275       clsstr   = _cls_all_re.getParen( 2 );
276       trcstr  = _cls_all_re.getParen( 3 );
277     }
278     clsstr = clsstr.intern();
279 
280     int trcId    = Integer.parseInt( trcstr, 10 );
281 
282     try {
283       next = readNextLine();    
284       while (next != null) {
285         if ( _cls_super_re.match( next )) {
286           sooper = _cls_super_re.getParen( 1 );
287         } else if ( _cls_loader_re.match( next )) {
288           loader = _cls_loader_re.getParen( 1 );
289         } else if ( _cls_static_name_re.match( next )) {
290           elem_name = _cls_static_name_re.getParen( 1 );
291           elem_name = elem_name.intern();
292           st_names.add( elem_name );
293           if ( _cls_static_addr_re.match( next ) ) {
294             elem_addr = _cls_static_addr_re.getParen( 1 );
295             //st_refs.add( Long.parseLong( elem_addr, 16 ) );
296             st_refs.add( convertAddrStringToLong( elem_addr ) );
297           }
298         } else {
299           if (_verbose) {
300             System. out. println( "####  Class unmatched: " + objstr + " " + clsstr);
301             System. out. println( "####  Class unmatched: " + next);
302           }
303           break;
304         }
305         next = readNextLine();
306       }
307     } catch ( Exception e ) {
308 			System. out. println ( "handleClass : Caught " + e + " on line : " + s );
309       System. out. println( "####  Class problem: s         = " + s);
310       System. out. println( "####  Class problem: sooper    = " + sooper);
311       System. out. println( "####  Class problem: loader    = " + loader);
312       System. out. println( "####  Class problem: elem_name = " + elem_name);
313       e. printStackTrace();
314       System.exit( -1 );
315     }
316     
317     if ( next != null) {
318       pushBack( next );
319     }
320 
321     //long addr = Long.parseLong( objstr, 16 );
322     long addr = convertAddrStringToLong( objstr );
323 
324     long sooper_addr  = 0;
325     long loader_addr  = 0;
326     if ( sooper != null ) {
327       //sooper_addr = Long.parseLong( sooper, 16 );
328       sooper_addr = convertAddrStringToLong( sooper );
329     }
330     if ( loader != null ) {
331       //loader_addr = Long.parseLong( loader, 16 );
332       loader_addr = convertAddrStringToLong( loader );
333     }
334 
335     // see if this class is already added...
336     HprofClassElement  cls = (HprofClassElement) _class_list.get( new HprofHeapElement(addr) );
337     if ( cls != null ) {
338       //assert clsstr.equals( cls.className() ) : "Classes are messed up" ;
339       if ( ! clsstr.equals( cls.className() ) ) {
340         System.out.println( "### Classes are messed up: " + clsstr + " != " + cls.className() );
341       }
342       
343       cls.completeClass( clsstr, trcId, sooper_addr, loader_addr, st_names, st_refs );
344     } else {
345       if ( _verbose ) {
346         System. out. println( "####  Adding Class class with no instances: " + clsstr);
347       }
348       cls = new HprofClassElement( addr, clsstr, trcId, sooper_addr, loader_addr, st_names, st_refs );
349       _class_list.put(cls, cls);
350       _classes.incrementAndGet();
351     }
352   }
353 
354 
355   public int handleArray( String s ) {
356     String objstr   = null;
357     String trcstr   = null;
358     String szstr    = null;
359     String nelemstr = null;
360     String idstr    = null;
361     String elem_idx;
362     String elem_addr;
363     String next       = null;
364     ArrayList elems   = new ArrayList();
365     long cls_addr     = 0;
366     
367     if ( _arr_all_re.match( s ) ) {
368       objstr  = _arr_all_re.getParen( 1 );
369       szstr   = _arr_all_re.getParen( 2 );
370       trcstr  = _arr_all_re.getParen( 3 );
371       nelemstr  = _arr_all_re.getParen( 4 );
372     }
373 
374     int trcId    = Integer.parseInt( trcstr, 10 );
375 
376     String clsstr = null;
377     HprofClassElement k = null;
378     
379     if ( _arr_type_both_re.match( s ) ) {
380       // it is a class array with a class addr
381       clsstr  = _arr_type_both_re.getParen( 1 );
382       idstr   = _arr_type_both_re.getParen( 2 );
383       //cls_addr = Long.parseLong( idstr, 16 );
384       cls_addr = convertAddrStringToLong( idstr );
385       
386       // intern here for pointer equality test and it helps with footprint reduction
387       clsstr = clsstr.intern();
388 
389       // It could be a basic type array denoted like "elem type=[B@570006b0" 
390       if ( MadmapMain.jdk14_compatible() ) {
391         if (( clsstr.charAt( 0 ) == '[' ) && ( clsstr.charAt( 1 ) != 'L' ) && ( clsstr.charAt( 1 ) != '[' )) {
392           k = Madmap.getFakeArrayClass( clsstr );
393         //} else if ((( clsstr.charAt( 0 ) == '[' ) && ( clsstr.charAt( 1 ) == 'L' )) || ( clsstr.charAt( 0 ) == 'L' )) {
394         } else {
395           // It is an array-of-objects type or multi-dimensional array, 
396           // add the class if not already added.
397           // This is similar to HprofObject.findOrCreateClass() but arrays 
398           // don't have nonstatic fields to record
399           k = (HprofClassElement)(_owner.getClasses()).get( new HprofHeapElement(cls_addr) );
400           if ( k == null ) {
401             k = new HprofClassElement( cls_addr, clsstr );
402             _owner.getClasses().put( k, k );
403             //System.out.println( "### Added object type array: " + clsstr + "@" + idstr );
404           }
405           
406           // Add a class for the array-of-objects type
407           // Use 1 - cls_addr as the class addr for this fake class, I think it is unlikely
408           // to collide with another class
409           long    arrayKlassAddr = 1 - cls_addr;
410           
411           // See if it is already added
412           HprofClassElement ak = (HprofClassElement)(_owner.getClasses()).get( new HprofHeapElement(arrayKlassAddr) );
413           if ( ak == null ) {
414             // Add the klass right now
415             String  arrayKlassName = new String( "[Array type]" + clsstr );            
416             arrayKlassName = arrayKlassName.intern();
417             ak = new HprofClassElement( arrayKlassAddr, arrayKlassName );
418             _owner.getClasses().put( ak, ak );
419             //System.out.println( "### Added object array klass: " + arrayKlassName + "@" + Long.toHexString( arrayKlassAddr ));
420           }
421           
422           // Record the array objects with its true array-of-objects type
423           k = ak;
424         }
425       }
426     } else {
427       // it is a basic type array with no class addr
428       clsstr    = matchAndGet( _arr_type_re2, s );
429       // intern here for pointer equality test and it helps with footprint reduction
430       clsstr = clsstr.intern();      
431       k = Madmap.getFakeArrayClass( clsstr );      
432     } 
433 
434     next = readNextLine();
435 
436     while ((next != null) && ( next.startsWith( "\t" ))) {
437       // skip the leading tab
438       String fields = next.substring( 1 );
439 
440       int len = 0;
441       while ( fields.charAt( len ) != '\t' ) {
442         len++;
443       }
444       
445       // skip tabs in between name and addr
446       while ( fields.charAt( len ) == '\t' ) {
447         len++;
448       }
449       String faddr = fields.substring( len );
450       elems.add( convertAddrStringToLong( faddr ) );
451 
452       next = readNextLine();
453     }
454 
455     if ( next != null) {
456       pushBack( next );
457     }
458 
459     long addr   = convertAddrStringToLong( objstr );
460     long nelems = Long.parseLong( nelemstr, 10 ); // base 10
461     long size   = Long.parseLong( szstr, 10 );    // base 10
462     
463     HprofHeapCollectable testObj = (HprofHeapCollectable) _heap_objects_table.get( new HprofHeapElement(addr) );
464     if ( testObj != null ) {
465       return -1;
466     }
467     
468     HprofArrayObject  arr = new HprofArrayObject( addr, clsstr, trcId, size, nelems, k, elems );
469     _heap_objects_table.put( arr, arr );
470     _arrays.incrementAndGet();
471     return 0;
472   }
473 
474   HprofClassElement findOrCreateClass( String klass, long klass_addr, long size, ArrayList field_names ) {
475   
476     assert size != 0 : "size should not be 0" ;
477   
478     HprofClassElement k = (HprofClassElement) getClasses().get( new HprofHeapElement(klass_addr) );
479     if ( k == null ) {
480       // Add the klass right now
481       k = new HprofClassElement( klass_addr, klass, size );
482       getClasses().put( k, k );
483     } else {
484       assert k.addr() == klass_addr : "klass addr is wrong" ;
485       
486       // instance size will be 0 if the class was created during 
487       // loading an array of objects of this type
488       if ( k.instanceSize() == 0 ) {
489         k.updateInstanceSize(size);
490       }
491     }
492 
493     return k;
494   }
495 
496   public int handleObject( String s ) {
497     //String objstr   = matchAndGet( _obj_begin_re, s );
498     String objstr   = null;
499     String trcstr   = null;
500     String clsstr   = null;
501     String clsaddrstr   = null;
502     String szstr    = null;
503     String elem     = null;
504     String id       = null;
505     String next     = null;
506     ArrayList elem_ids   = new ArrayList();
507     ArrayList elem_names = new ArrayList();
508 
509     if ( _obj_all_re.match( s ) ) {
510       objstr      = _obj_all_re.getParen( 1 );
511       szstr       = _obj_all_re.getParen( 2 );
512       trcstr    = _obj_all_re.getParen( 3 );
513       clsstr      = _obj_all_re.getParen( 4 );
514       clsaddrstr  = _obj_all_re.getParen( 5 );
515     }
516 
517     clsstr  = clsstr.intern();
518     next    = readNextLine();
519     int trcId    = Integer.parseInt( trcstr, 10 );
520     
521     while ((next != null) && ( next.startsWith( "\t" ))) {
522       // skip the leading tab
523       String fields = next.substring( 1 );
524 
525       int len = 0;
526       while ( fields.charAt( len ) != '\t' ) {
527         len++;
528       }
529       
530       String fname = fields.substring( 0, len );
531       fname = fname.intern();
532       elem_names.add( fname );
533       // skip tabs in between name and addr
534       while ( fields.charAt( len ) == '\t' ) {
535         len++;
536       }
537       String faddr = fields.substring( len );
538       elem_ids.add( convertAddrStringToLong( faddr ) );
539 
540       next = readNextLine();
541     }
542 
543     if ( next != null) {
544       pushBack( next );
545     }
546 
547     if ( clsaddrstr == null ) {
548         System. out. println( "####  Object clsaddrstr is null: " + objstr);
549     }
550     
551     long addr     = convertAddrStringToLong( objstr );
552 
553     HprofHeapCollectable testObj = (HprofHeapCollectable) _heap_objects_table.get( new HprofHeapElement(addr) );
554     if ( testObj != null ) {
555       // debug 080527
556       //System. out. println( "#### #################################################: ");
557       //System. out. println( "#### handleObject Found object already in table: " + Long.toHexString(addr));
558       //System. out. println( "#### handleObject started with: " + s);
559       //testObj.print();
560       return -1;
561     }
562     
563     long cls_addr = convertAddrStringToLong( clsaddrstr );
564     long size     = Long.parseLong( szstr, 10 );
565     
566     if ( ! MadmapMain.getSaveMemberNames() ) {
567       elem_names = null;
568     }
569     
570     // Dont store an empty array
571     if ( elem_ids.size() == 0 ) {
572       elem_ids    = null;
573       elem_names  = null;
574     }
575     
576 
577     HprofClassElement k = findOrCreateClass( clsstr, cls_addr, size, elem_names );
578     
579     HprofObject ho = new HprofObject( addr, clsstr, k, size, trcId, elem_names, elem_ids );
580     
581     if (( elem_names != null ) && ( elem_names.size() != 0 )) {
582     	ho.set_member_name_indexes( k.setNonstaticFieldNames( elem_names ) );
583     }
584         
585     //_heap_objects_table.put( (int) addr, ho );
586     _heap_objects_table.put( ho, ho );
587     _objects.incrementAndGet();
588     return 0;
589   }
590 
591 
592   public void handleRoot( String s ) {
593     int    i       = 0;
594     String objstr  = matchAndGet( _root_begin_re, s );
595     String kindstr = matchAndGet( _root_kind_re, s );
596     String idstr    = null;
597     String trcstr   = null;
598     String classnamestr = null;
599     
600     if ( kindstr == null ) {
601       if ( _root_kind_unknown_re.match(s) ) {
602         kindstr = "<unknown>";
603       } else if ( _root_kind_busymon_re.match(s) ) {
604         kindstr = "<busy monitor>";
605       }
606     }
607     
608     kindstr = kindstr.intern();
609     
610     if ( kindstr.equals("<JNI global ref>") ) {
611       idstr   = matchAndGet( _root_id_re, s );
612       trcstr  = matchAndGet( _root_trace_re, s );
613     } else if ( kindstr.equals("<unknown>") ) {
614     } else if ( kindstr.equals("<Java stack>") ) {
615     } else if ( kindstr.equals("<thread block>") ) {
616     } else if ( kindstr.equals("<JNI local ref>") ) {
617     } else if ( kindstr.equals("<thread>") ) {
618     } else if ( kindstr.equals("<busy monitor>") ) {
619     } else if ( kindstr.equals("<native stack>") ) {
620       // nothing to do
621     } else if ( kindstr.equals("<system class>") ) {
622       classnamestr = matchAndGet( _root_classname_re, s );
623       //System. out. println( "### classnamestr root : " + classnamestr );
624       classnamestr = classnamestr.intern();
625     } else {
626       System. out. println( "### unknown root : " + s );
627     }
628     
629     //System. out. println( "Adding root: " + objstr + " " + kindstr);
630 
631     HprofRoot rt = new HprofRoot( convertAddrStringToLong( objstr ), kindstr );
632     _roots_list.add( rt );
633   }
634   
635   
636   public void handleHeapDumpStart( String s ) {
637     int    i       = 0;
638     String objstr  = matchAndGet( _heap_dump_objects_re, s );
639     String bytestr = matchAndGet( _heap_dump_bytes_re, s );
640     
641     System. out. println( "Heap dump objects : " + objstr );
642     System. out. println( "Heap dump bytes   : " + bytestr );
643   }
644   
645   
646   public void handleThreadStart( String s ) {
647     String objstr  = matchAndGet( thread_start_obj, s );
648     String idstr   = matchAndGet( thread_start_id, s );
649     String namestr = matchAndGet( thread_start_name, s );
650     String grpstr  = matchAndGet( thread_start_group, s );
651         
652     if ( objstr != null && idstr != null && namestr != null && grpstr != null ) {
653       long addr = convertAddrStringToLong( objstr );
654       int id    = Integer.parseInt( idstr, 10 );
655       
656       HprofThreadData td = new HprofThreadData( namestr, id, addr, grpstr );
657       _threads_list.put( (int) addr, td );
658     } else {
659       System. out. println( "### Malformed thread ??: " + s );
660     }
661   }
662 
663 
664   public void handleThreadEnd( String s ) {
665   }
666 
667 
668   public int handleHeapDumpEnd( String s ) {
669     // Stop processing here in case the input file has multiple dumps
670     if ( MadmapMain.verbose() ) {
671       System. out. println( "Found the end: " + s );
672     }
673     return -1;
674   }
675 
676 
677   public void handleTrace( String s ) {
678     String traceid = matchAndGet( _stack_trace_title_re, s );;
679     String next    = null;
680     String elem    = null;
681     Vector backtrace = new Vector();
682     HprofStackTraceData sd = null;
683     
684     if ( traceid == null ) {
685       System. out. println( "### Malformed trace title ??: " + s );
686       return;
687     }
688   
689     next = readNextLine();
690     while ((next != null) && ( _stack_trace_item_re.match( next ))) {
691       elem = _stack_trace_item_re.getParen( 1);
692       elem = elem.intern();
693       backtrace.add( elem );
694       next = readNextLine();
695     } 
696     
697     if ( next != null) {
698       pushBack( next );
699     }
700 
701     // Consider option to suppress save traces to save footprint
702     int id    = Integer.parseInt( traceid, 10 );
703     sd = new HprofStackTraceData( id, backtrace );
704     getStackTraces().put( id, sd );
705   }
706 
707 
708   public void pushBack( String s ) {
709     _pushed_string = s;
710   }
711 
712 
713   public String readNextLine() {
714 	  try {
715 		  if ( _pushed_string != null ) {
716 			  String s = _pushed_string;
717 			  _pushed_string = null;
718 			  return s;
719 		  } else {
720 			  _linesSeen++;
721 			  if ( MadmapMain.verbose() && ((_linesSeen % 200000) == 0)) {
722 				  float rate = (float) _linesSeen / (float) elapsedTime();
723 				  System. out. println( elapsedTime() + ": Processed " + _linesSeen + " lines from " + _startOffset + ", " + rate + "/sec" );
724 			  }
725 			  if (( ! MadmapMain.noGUI()) && ( _readerId == 0 )) {
726 				  _owner.getWindow().getProgressBar().setValue((int)_linesSeen);
727 				  _owner.getWindow().updateMemoryProgressBar();          
728 			  }
729 
730 			  String ln = _bfr. readLine();
731 			  //System. out. println( ln );
732 			  //return _bfr. readLine();
733 			  return ln;
734 		  }
735 	  } catch ( Exception ie ) {
736 		  System. out. println ( "readNextLine : Caught " + ie );
737 		  return null;
738 	  }
739   }
740   
741 
742   public void readAndProcessLines(int max) {
743     long    linesRead   = 0;
744     String  theInput    = null;
745     int     result      = 0;
746     try {
747       theInput = _bfr. readLine();
748       while((theInput != null) && (result == 0)) {
749         result = processLine( theInput );        
750         theInput = readNextLine();
751       }
752     } catch (OutOfMemoryError e) { 
753       JOptionPane.showMessageDialog(_owner.getWindow(), 
754           "Sorry, cannot continue. Relaunch Madmap with larger heap size.", 
755           "OutOfMemoryError", JOptionPane.ERROR_MESSAGE);
756       System.out.println("OutOfMemoryError in reader thread. ");
757       e.printStackTrace();
758       System.exit(-1);
759     } catch ( Throwable ie ) {
760       System. out. println ( "processLine : Caught " + ie + " near line " + _linesSeen + " : " + theInput );
761       ie.printStackTrace();
762       System.exit(-1);
763     }
764   }
765 
766 	public int processLine(String theInput) {
767 
768     // This needs fixing for all method returns 
769 
770     //if( _obj_begin_re. match( theInput ) == true ) {
771     //if( theInput.startsWith( "OBJ" ) ) {
772     if( theInput.startsWith( objStart ) ) {
773       //System. out. println( "###### matched object: " + theInput );
774       return handleObject( theInput );
775     //} else if( _arr_begin_re. match( theInput ) == true ) {
776     //} else if( theInput.startsWith( "ARR" ) ) {
777     } else if( theInput.startsWith( arrStart ) ) {
778       //System. out. println( "###### matched object: " + theInput );
779       return handleArray( theInput );
780     //} else if( _cls_begin_re. match( theInput ) == true ) {
781     //} else if( theInput.startsWith( "CLS" )  ) {
782     } else if( theInput.startsWith( clsStart )  ) {
783       //System. out. println( "###### matched class: " + theInput );
784       handleClass( theInput );
785     //} else if( _root_begin_re. match( theInput ) == true ) {
786     } else if( theInput.startsWith( "ROOT " ) ) {
787       //System. out. println( "###### matched root: " + theInput );
788       handleRoot( theInput );
789     } else if( stack_trace_re. match( theInput ) == true ) {
790     //} else if( theInput.startsWith( "TRACE " ) ) {
791       //System. out. println( "###### matched trace: " + theInput );
792       handleTrace( theInput );
793     } else if( thread_start_re. match( theInput ) == true ) {
794       //System. out. println( "###### matched thd start: " + theInput );
795       handleThreadStart( theInput );
796     } else if( thread_end_re. match( theInput ) == true ) {
797       handleThreadEnd( theInput );
798     } else if( _heap_dump_begin_re. match( theInput ) == true ) {
799       handleHeapDumpStart( theInput );
800     } else if( _heap_dump_end_re. match( theInput ) == true ) {
801       handleHeapDumpEnd( theInput );
802     } else {
803       //if ( Madmap.verbose() ) {
804       //  System. out. println( "###### unmatched: line " + linesSeen + " : " + theInput  );
805       //}
806     }
807     return 0;
808 	}
809 
810 
811   public float elapsedTime() {
812     return (float)(System.currentTimeMillis() - _startTime)/(float)1000.0;
813   }
814   	}
815 
816 }
817