这篇答案是对@Will-Hartung的补充。我也使用了同样的方法来诊断我的一个内存泄漏问题,想分享细节以帮助其他人节省时间。
核心思路是让Postgres绘制每个类别的时间和内存使用情况图表,并绘制总增长率线条,识别增长最快的对象。
^
|
s | Legend:
i | * - data point
z | -- - trend
e |
( |
b | *
y | --
t | --
e | * -- *
s | --
) | *-- *
| -- *
| -- *
--------------------------------------->
time
将您的堆转储(需要多个)转换为适合Postgres消费的格式,以从堆转储格式中获得方便:
num
----------------------------------------------
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
...
将每个堆转储的日期时间保存到csv文件中:
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
...
使用此脚本:
使用此脚本:
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;
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 TABLE heap_histogram (
histwhen timestamp without time zone NOT NULL,
class character varying NOT NULL,
instances integer NOT NULL,
bytes integer NOT NULL
);
将数据复制到您的新表中
\COPY heap_histogram FROM 'heap.csv' WITH DELIMITER ',' CSV ;
运行倾斜查询来对字节数量进行查询:
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
;
解读结果:
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
斜率是每秒增加的字节数(因为时间单位为秒)。如果使用实例代替大小,则表示每秒添加的实例数。
我其中一行创建joe.schmoe.BusinessObject的代码导致了内存泄漏。它在创建对象并将其附加到数组时未检查该对象是否已存在。其他对象也与BusinessObject一起在泄漏的代码附近创建。