この回答は、@Will-Hartung を拡張したものです。私は同じプロセスを適用してメモリ リークの 1 つを診断し、詳細を共有することで他の人の時間を節約できると考えました。
アイデアは、Postgres の「プロット」時間と各クラスのメモリ使用量を比較し、成長を要約する線を引き、最も速く成長しているオブジェクトを特定することです。
^
|
s | Legend:
i | * - data point
z | -- - trend
e |
( |
b | *
y | --
t | --
e | * -- *
s | --
) | *-- *
| -- *
| -- *
--------------------------------------->
time
ヒープ ダンプ (複数必要) を、postgres がヒープ ダンプ形式から使用するのに便利な形式に変換します。
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
...
各ヒープ ダンプの日時を含む 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
...
このスクリプトの使用:
# 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 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
勾配は、1 秒あたりに追加されるバイト数です (エポックの単位が秒であるため)。サイズの代わりにインスタンスを使用する場合、それは 1 秒あたりに追加されるインスタンスの数です。
この joe.schmoe.BusinessObject を作成するコード行の 1 つが、メモリ リークの原因でした。オブジェクトを作成し、既に存在するかどうかを確認せずに配列に追加していました。他のオブジェクトも、リークしているコードの近くで BusinessObject とともに作成されました。