Oracle® Solaris Studio 12.4: Discover および Uncover ユーザーズガイド

印刷ビューの終了

更新: 2015 年 12 月
 
 

discover API と環境変数

コード内に指定できる discover API と環境変数がいくつか用意されています。

discover API

Oracle Solaris Studio 12.4 には、プログラムから呼び出してメモリーリークやメモリー割り当ての情報を受け取ることができる 6 つの新しい discover 関数が実装されています。これらの関数は、stderr に情報を出力します。discover は、デフォルトでプログラム出力の最後に、プログラム内のメモリーリークを含む最終的なメモリーレポートを出力します。これらの API を使用するには、アプリケーションのソースファイルに discover 用のヘッダーファイルをインクルードする必要があります (#include <discoverAPI.h>)。

関数と報告される内容は次のとおりです。

discover_report_all_inuse()

すべてのメモリー割り当てを報告します

discover_report_unreported_inuse()

以前に報告されていないすべてのメモリー割り当てを報告します。

discover_mark_all_inuse_as_reported()

今までに報告されたすべてのメモリー割り当てをマークします。

discover_report_all_leaks()

すべてのメモリーリークを報告します。

discover_report_unreported_leaks()

以前に報告されていないすべてのメモリーリークを報告します。

discover_mark_all_leaks_as_reported()

今までに報告されたすべてのメモリーリークをマークします

このセクションでは、discover API の使用方法について説明します。


注 -  discover API は ADI モードで動作しません。

discover API によるメモリーリークの検出

discover は、コード内に指定した関数ごとに、メモリーが割り当てられた場所のスタックを報告します。メモリーリークとは、プログラム内で到達不可能な割り当てメモリーのことです。

次の例は、これらの API の使用方法を示しています。

$ cat -n tdata.C
     1    #include <discoverAPI.h>
     2   
     3    void foo()
     4    {
     5      int *j = new int;
     6    }
     7   
     8    int main()
     9    {
    10      foo();
    11      discover_report_all_leaks();
    12   
    13      foo();
    14      discover_report_unreported_leaks();
    15   
    16      return 0;
    17    }
$ CC -g tdata.C
$ discover -w - a.out
$ a.out

次の例は、予想される出力を示しています。

******** discover_report_all_leaks() Report ********
1 allocation at 1 location left on the heap with a total size of 4 bytes
LEAK 1: 1 allocation with total size of 4 bytes 
void*operator new(unsigned) + 0x36 
void foo() + 0x5e  <tdata.C:5>
2:
3:    void foo()
4:    {
5:=>    int *j = new int;
6:    }
7:
8:    int main() 
main()+0x1a  <tdata.C:10>
9:    {
10:=>    foo();
11:      discover_report_all_leaks();           
12:   
13:      foo();         _start() + 

**********************************************************
******** discover_report_unreported_leaks() Report ********
1 allocation at 1 location left on the heap with a total size of 4 bytes
LEAK 1: 1 allocation with total size of 4 bytes 
void*operator new(unsigned) + 0x36
void foo() + 0x5e  <tdata.C:5>
2: 
3:    void foo()
4:    {
5:=>    int *j = new int;
6:    }
7:
8:int main()
main() + 0x24  <tdata.C:13>
10:      foo();
11:      discover_report_all_leaks();
12:
13:=>    foo();
14:      discover_report_unreported_leaks();
15:
16:return 0;
_start() + 0x71 

**********************************************************
***************** Discover Memory Report *****************
2 allocations at 2 locations left on the heap with a total size of 8     bytes
LEAK 1: 1 allocation with total size of 4 bytes
void*operator new(unsigned) + 0x36
void foo() + 0x5e  <tdata.C:5>
2:
3:    void foo()
4:    {
5:=>    int *j = new int;
6:    }
7:
8:    int main() 
main() +    0x1a  <tdata.C:10>
7:
8:    int main()
9:    {             10:=>    foo();
11:      discover_report_all_leaks();
12:   
13:      foo();         _start() + 0x71 
LEAK 2: 1 allocation with total size of 4 bytes
void*operator new(unsigned) + 0x36 
void foo() + 0x5e  <tdata.C:5>
2:
3:    void foo()
4:    {
5:=>    int *j = new int;
6:    }
7:
8:    int main()
main() + 0x24  <tdata.C:13>
10:      foo();
11:      discover_report_all_leaks();
12:
13:=>    foo();
14:         discover_report_unreported_leaks();
15:
16:      return 0;
_start() + 0x71 

DISCOVER SUMMARY:
unique errors   : 0 (0 total)
unique warnings : 0 (0 total)

サーバーまたは長時間実行プログラム内のリークの検出

終了することがない長時間実行プログラムまたはサーバーがある場合は、コード内に呼び出しを配置しなくても、dbx を使用していつでもこれらの discover 関数を呼び出すことができます。プログラムは、少なくとも –l オプションを使用して discover の軽量モードで実行されている必要があります。dbx は実行中のプログラムに接続できます。次の例は、長時間実行プログラム内のリークを検出する方法を示しています。

使用例 1  長時間実行プログラム内の 2 つのリークの検出

この例で、a.out ファイルは 2 つのプロセスを持つ長時間実行プログラムであり、各プロセスにリークが 1 つずつあります。各プロセスにはプロセス ID が割り当てられています。

次の rl スクリプトには、このプログラムに対して報告されていないメモリーリークを報告するように要求するコマンドが含まれています。

#!/bin/sh
dbx - $1 > /dev/null 2> &1 << END
call discover_report_unreported_leaks()
exit
END

プログラムとスクリプトが用意できたら、discover を使用してプログラムを実行できます。

% discover -l -w - a.out
% a.out
8252: Parent allocation 64
8253: Child allocation 32

別個の端末ウィンドウで、親プロセスに対してスクリプトを実行できます。

% rl 8252

プログラムは親プロセスに関して次の情報を報告します。

******** discover_report_unreported_leaks() Report ********

1 allocation at 1 location left on the heap with a total size of 64 bytes

    LEAK 1: 1 allocation with total size of 64 bytes
    main() + 0x1e  <xx.c:17>
        14:   
        15:      if (child > 0) {
        16:   
        17:=>      void *p = malloc(64);
        18:        printf("%jd: Parent allocation 64\n", (intmax_t)getpid());
        19:        p = 0;
        20:        for (int j=0; j < 1000; j++) sleep(1);
    _start() + 0x66


**********************************************************

子プロセスに対して再度プロセスを実行します。

% rl 8253

プログラムは子プロセスに関して次の情報を報告します。

******** discover_report_unreported_leaks() Report ********

1 allocation at 1 location left on the heap with a total size of 32 bytes

    LEAK 1: 1 allocation with total size of 32 bytes
    main() + 0x80  <xx.c:24>
        21:      }
        22:   
        23:      else {
        24:=>      void *p = malloc(32);
        25:        printf("%jd: Child allocation 32\n", (intmax_t)getpid());
        26:        p = 0;
        27:        for (int j=0; j < 1000; j++) sleep(1);
    _start() + 0x66


**********************************************************

スクリプトを繰り返し使用して、新しいリークを検出できます。

SUNW_DISCOVER_OPTIONS 環境変数

計測対象バイナリの実行時の動作を変更するには、SUNW_DISCOVER_OPTIONS 環境変数に、コマンド行オプション –a–A–b–e–E–f–F–H–l–L–m–P–S、および –w のリストを設定します。たとえば、レポートされるエラー数を 50 に変更し、レポート内のスタックの深さを 3 に制限する場合、環境変数を次のように設定します。

–e 50 –s 3

SUNW_DISCOVER_FOLLOW_FORK_MODE 環境変数

デフォルトでは、discover で計測機構を組み込んだバイナリが実行中にフォークした場合、discover は親および子プロセスからメモリーアクセスエラーのデータを収集し続けます。つまり、デフォルトの動作は both です。たとえば、discover でフォークを追跡し、子プロセスからメモリーアクセスデータを収集する場合は、SUNW_DISCOVER_FOLLOW_FORK_MODE 環境変数を次のように設定します。

–F child