1Test::LeakTrace::JA(3)User Contributed Perl DocumentationTest::LeakTrace::JA(3)
2
3
4
6 Test::LeakTrace::JA - メモリリークを追跡する
7
9 This document describes Test::LeakTrace version 0.16.
10
12 use Test::LeakTrace;
13
14 # simple report
15 leaktrace{
16 # ...
17 };
18
19 # verbose output
20 leaktrace{
21 # ...
22 } -verbose;
23
24 # with callback
25 leaktrace{
26 # ...
27 } sub {
28 my($ref, $file, $line) = @_;
29 warn "leaked $ref from $file line\n";
30 };
31
32 my @refs = leaked_refs{
33 # ...
34 };
35 my @info = leaked_info{
36 # ...
37 };
38
39 my $count = leaked_count{
40 # ...
41 };
42
43 # standard test interface
44 use Test::LeakTrace;
45
46 no_leaks_ok{
47 # ...
48 } "description";
49
50 leaks_cmp_ok{
51 # ...
52 } '<', 10;
53
55 PerlのGCはリファレンスカウンタを用いたものなので,オブジェクトが開放されるタイミングが明確であることや体感速度が高速であることなど数々の利点があります。
56 その一方で,循環参照を開放できないこと,Cレベルでの操作でミスしやすいなど,問題点がいくつかあります。それらの問題点のほとんどはメモリリークに関することですから,メモリリークを追跡することは非常に重要な課題です。
57
58 "Test::LeakTrce"はメモリリークを追跡するためのいくつかのユーティリティと"Test::Builder"ベースのテスト関数を提供します。このモジュールはPerlのメモリアロケーションシステムであるアリーナを走査するため,SVに関することであれば与えられたコードのどんなメモリリークでも検出できます。つまり,Perlレベルでの循環参照を始めとして,XSモジュールやPerl自身のバグによるメモリリークを追跡することができます。
59
60 ここでリークとは,特定のスコープ内で新たに作成されて,そのスコープ終了後にも残っている値を意味します。これは,新たに作成されたグローバルな値やPerlが暗黙のうちに作成するキャッシュの値も含みます。たとえば,リーク追跡を行っている最中に新たに名前つきサブルーチンを定義すれば,それはリークとみなされます。また,継承したメソッドを呼び出したり,オブジェクトを作成したりするだけで様々なキャッシュが生成され,リークが報告される可能性があります。
61
63 Exported functions
64 "leaked_info { BLOCK }"
65
66 BLOCKを実行し,追跡結果をリストで返します。
67 結果はリークした値のリファレンス,ファイル名,行番号の三要素を持つ配列,つまり"[$ref,
68 $file, $line]"のリストとなっています。
69
70 なお,この関数はPerl内部で使用する値を返す可能性があります。そのような内部用の値を変更するとPerl実行環境に致命的な影響を与える可能性があるので注意してください。また,配列やハッシュの要素として,リファレンスではない配列やハッシュそれ自体が含まれる可能性があります。そのような値は通常Perlレベルで操作することができません。たとえば"Data::Dumper"などで出力することはできません。
71
72 "leaked_refs { BLOCK }"
73
74 BLOCKを実行し,リークしたSVのリファレンスのリストを返します。
75
76 "map{ $_->[0] } leaked_info{ BLOCK }"と同じですが,より高速です。
77
78 "leaked_count { BLOCK }"
79
80 BLOCKを実行し,リークしたSVのリファレンスの個数を返します。
81
82 "leaked_info()"と"leaked_refs()"もスカラコンテキストでは個数を返しますが,
83 "leaked_count()"はコンテキストに依存しません。
84
85 "leaktrace { BLOCK } ?($mode | \&callback)"
86
87 BLOCKを実行し,その中で起きたメモリリークを*STDERRに報告します。
88
89 メモリリークの報告は$modeで指定したモードに従います。
90 受け付ける$modeは以下の通りです:
91
92 -simple
93 デフォルトのモードです。リークしたSVの型とアドレス,ファイル名,行番号を報告します。
94
95 -sv_dump
96 -simpleに加えて,"sv_dump()"でSVの中身をダンプします。
97 これは,"Devel::Peek::Dump()"の出力とほぼ同じです。
98
99 -lines
100 -simpleに加えて,リークしていると見られる行の周辺を出力します。
101
102 -verbose
103 -simpleと-sv_dumpと-linesの全てを出力します。
104
105 より細かな制御のためにコールバックを指定することもできます。
106 \&callbackはリークしたSV毎に呼び出され,その引数はリークしたSVのリファレンス,ファイル名,行番号の3つです。
107
108 "no_leaks_ok { BLOCK } ?$description"
109
110 BLOCKにメモリリークがないことテストします。
111 これは"Test::Builder"ベースのテスト関数です。
112
113 なお,BLOCKは複数回実行されます。これは,初回の実行でキャッシュを用意する可能性を考慮するためです。
114
115 "leaks_cmp_ok { BLOCK } $cmp_op, $count, ?$description"
116
117 BLOCKのメモリリーク数と特定の数値を比較するテストを行います。
118 これは"Test::Builder"ベースのテスト関数です。
119
120 なお,BLOCKは複数回実行されます。これは,初回の実行でキャッシュを用意する可能性を考慮するためです。
121
122 Script interface
123 "Devel::LeakTrace"と同様に,スクリプトのリーク追跡のために"Test::LeakTrace::Script"が提供されます。"use
124 Test::LeakTrace::Script"宣言の引数は"leaktrace()"と同じです。
125
126 $ TEST_LEAKTRACE=-sv_dump perl -MTest::LeakTrace::Script script.pl
127 $ perl -MTest::LeakTrace::Script=-verbose script.pl
128
129 #!perl
130 # ...
131
132 use Test::LeakTrace::Script sub{
133 my($ref, $file, $line) = @_;
134 # ...
135 };
136
137 # ...
138
140 Testing modules
141 以下はモジュールのメモリリークをチェックするテストスクリプトのテンプレートです。
142
143 #!perl -w
144 use strict;
145 use constant HAS_LEAKTRACE => eval{ require Test::LeakTrace };
146 use Test::More HAS_LEAKTRACE ? (tests => 1) : (skip_all => 'require Test::LeakTrace');
147 use Test::LeakTrace;
148
149 use Some::Module;
150
151 leaks_cmp_ok{
152 my $o = Some::Module->new();
153 $o->something();
154 $o->something_else();
155 } '<', 1;
156
158 "Test::LeakTrace"はアリーナを走査します。アリーナとは,Perlが作成するSVのためのメモリアロケーションシステムであり,sv.cで実装されています。
159 アリーナの走査にはsv.cにある"S_visit()"のコードを元にしたマクロを用いています。
160
161 さて,アリーナを走査すれば,メモリリークの検出そのものは簡単にできるように思えます。まず,コードブロックを実行する前に一度アリーナを走査し,全てのSVに「使用済み」の印を付けておきます。次に,コードブロック実行後にもう一度アリーナを走査し,使用済みの印がついていないSVがあれば,それはコードブロック内で作成され,開放されなかったSVだと考えます。あとはそれを報告するだけです。実際には,SVに対して使用済みの印を付けるスペースがないため,インサイドアウト法を応用して外部のコンテナに使用済みの印を保存します。
162 これを仮にPerlコードで書くと以下のようになります。
163
164 my %used_sv;
165 foreach my $sv(@ARENA){
166 $used_sv{$sv}++;
167 }
168 $block->();
169
170 my @leaked
171 foreach my $sv(@ARENA){
172 if(not exists $used_sv{$sv}){
173 push @leaked, $sv;
174 }
175 }
176 say 'leaked count: ', scalar @leaked;
177
178 リークしたSVを得るだけならこの方法で十分です。実際,"leaked_refs()"と"leaked_count()"はこのような方法でリークしたSVやその個数を調べています。
179
180 しかし,リークしたSVのステートメントの情報,つまりファイル名や行番号を得るためにはこれだけでは不十分です。Perl
181 5.10以降にはSVが作成されたときのステートメント情報を追跡する機能があるのですが,この機能を利用するためには,コンパイラオプションとしてに"-DDEBUG_LEAKING_SCALARS"を与えてPerlをビルドしなければなりません。
182
183 そこで,"Test::LeakTrace"では拡張可能な"PL_runops"を利用して,Perl
184 VMがOPコードを実行する1ステートメント毎にアリーナを走査し,ステートメント情報を記録します。これは,1ステートメント毎にマーク&スイープのような処理を行うのに等しく,非常に時間が掛かります。しかし,Perlを特殊な条件の下でビルドする必要もなく,バージョンに依存した機能もほとんど使用しないため,多くの環境で動かすことができます。
185
186 また,"no_leaks_ok()"のようなテスト関数はまず"leaked_count()"でリークしたSVの個数を得てから,必要に応じてリークした位置を特定するために"leaktrace()"を実行するため,テストが成功する限りは時間の掛かる追跡処理はしません。
187
189 Perl 5.8.1 or later, and a C compiler.
190
192 "Test::LeakTrace"は"Devel::Cover"と一緒に動かすことはできません。
193 したがって,"Devel::Cover"の元で動いていることが検出されると,テスト関数は何も行わずにテストをパスさせます。
194
196 No bugs have been reported.
197
198 Please report any bugs or feature requests to the author.
199
201 Devel::LeakTrace.
202
203 Devel::LeakTrace::Fast.
204
205 Test::TraceObject.
206
207 Test::Weak.
208
209 For guts:
210
211 perlguts.
212
213 perlhack.
214
215 sv.c.
216
218 Goro Fuji <gfuji(at)cpan.org>.
219
221 Copyright (c) 2009, Goro Fuji. Some rights reserved.
222
223 This library is free software; you can redistribute it and/or modify it
224 under the same terms as Perl itself.
225
226
227
228perl v5.32.0 2020-07-28 Test::LeakTrace::JA(3)