Method for finding memory leak in large Java heap dumps

后端 未结 8 741
隐瞒了意图╮
隐瞒了意图╮ 2020-12-22 19:05

I have to find a memory leak in a Java application. I have some experience with this but would like advice on a methodology/strategy for this. Any reference and advice is we

相关标签:
8条回答
  • 2020-12-22 19:43

    Take a look at Eclipse Memory Analyzer. It's a great tool (and self contained, does not require Eclipse itself installed) which 1) can open up very large heaps very fast and 2) has some pretty good automatic detection tools. The latter isn't perfect, but EMA provides a lot of really nice ways to navigate through and query the objects in the dump to find any possible leaks.

    I've used it in the past to help hunt down suspicious leaks.

    0 讨论(0)
  • 2020-12-22 19:50

    This answer expands upon @Will-Hartung's. I applied to same process to diagnose one of my memory leaks and thought that sharing the details would save other people time.

    The idea is to have postgres 'plot' time vs. memory usage of each class, draw a line that summarizes the growth and identify the objects that are growing the fastest:

        ^
        |
    s   |  Legend:
    i   |  *  - data point
    z   |  -- - trend
    e   |
    (   |
    b   |                 *
    y   |                     --
    t   |                  --
    e   |             * --    *
    s   |           --
    )   |       *--      *
        |     --    *
        |  -- *
       --------------------------------------->
                          time
    

    Convert your heap dumps (need multiple) into a format this is convenient for consumption by postgres from the heap dump format:

     num     #instances         #bytes  class name 
    ----------------------------------------------
       1:       4632416      392305928  [C
       2:       6509258      208296256  java.util.HashMap$Node
       3:       4615599      110774376  java.lang.String
       5:         16856       68812488  [B
       6:        278914       67329632  [Ljava.util.HashMap$Node;
       7:       1297968       62302464  
    ...
    

    To a csv file with a the datetime of each heap dump:

    2016.09.20 17:33:40,[C,4632416,392305928
    2016.09.20 17:33:40,java.util.HashMap$Node,6509258,208296256
    2016.09.20 17:33:40,java.lang.String,4615599,110774376
    2016.09.20 17:33:40,[B,16856,68812488
    ...
    

    Using this script:

    # Example invocation: convert.heap.hist.to.csv.pl -f heap.2016.09.20.17.33.40.txt -dt "2016.09.20 17:33:40"  >> heap.csv 
    
     my $file;
     my $dt;
     GetOptions (
         "f=s" => \$file,
         "dt=s" => \$dt
     ) or usage("Error in command line arguments");
     open my $fh, '<', $file or die $!;
    
    my $last=0;
    my $lastRotation=0;
     while(not eof($fh)) {
         my $line = <$fh>;
         $line =~ s/\R//g; #remove newlines
         #    1:       4442084      369475664  [C
         my ($instances,$size,$class) = ($line =~ /^\s*\d+:\s+(\d+)\s+(\d+)\s+([\$\[\w\.]+)\s*$/) ;
         if($instances) {
             print "$dt,$class,$instances,$size\n";
         }
     }
    
     close($fh);
    

    Create a table to put the data in

    CREATE TABLE heap_histogram (
        histwhen timestamp without time zone NOT NULL,
        class character varying NOT NULL,
        instances integer NOT NULL,
        bytes integer NOT NULL
    );
    

    Copy the data into your new table

    \COPY heap_histogram FROM 'heap.csv'  WITH DELIMITER ',' CSV ;
    

    Run the slop query against size (num of bytes) query:

    SELECT class, REGR_SLOPE(bytes,extract(epoch from histwhen)) as slope
        FROM public.heap_histogram
        GROUP BY class
        HAVING REGR_SLOPE(bytes,extract(epoch from histwhen)) > 0
        ORDER BY slope DESC
        ;
    

    Interpret the results:

             class             |        slope         
    ---------------------------+----------------------
     java.util.ArrayList       |     71.7993806279174
     java.util.HashMap         |     49.0324576155785
     java.lang.String          |     31.7770770326123
     joe.schmoe.BusinessObject |     23.2036817108056
     java.lang.ThreadLocal     |     20.9013528767851
    

    The slope is bytes added per second (since the unit of epoch is in seconds). If you use instances instead of size, then that's the number of instances added per second.

    My one of the lines of code creating this joe.schmoe.BusinessObject was responsible for the memory leak. It was creating the object, appending it to an array without checking if it already existed. The other objects were also created along with the BusinessObject near the leaking code.

    0 讨论(0)
提交回复
热议问题