JVM メモリリークでは JDK の jstat や jmap で原因を調査できます。C/C++ では valgrind の Memcheck ツールが利用できます。valgrind には複数のツールが含まれており既定のツールが Memcheck です。他のツールを利用する場合は --tool
オプションで指定します。
必須ではありませんが -g -O0
オプションでコンパイルすると、valgrind の出力にファイル名および行番号が含まれるようになります。
main.cpp
#include <iostream>
int main() {
int* arr = new int[10];
arr[10] = 1;
return 0;
}
実行例
g++ -Wall -O0 -g main.cpp
valgrind --leak-check=yes a.out
出力例
==21582== Memcheck, a memory error detector
==21582== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==21582== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==21582== Command: a.out
==21582==
==21582== Invalid write of size 4
==21582== at 0x109173: main (main.cpp:5)
==21582== Address 0x4d59ca8 is 0 bytes after a block of size 40 alloc'd
==21582== at 0x483650F: operator new[](unsigned long) (vg_replace_malloc.c:423)
==21582== by 0x109166: main (main.cpp:4)
==21582==
==21582==
==21582== HEAP SUMMARY:
==21582== in use at exit: 40 bytes in 1 blocks
==21582== total heap usage: 2 allocs, 1 frees, 72,744 bytes allocated
==21582==
==21582== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1
==21582== at 0x483650F: operator new[](unsigned long) (vg_replace_malloc.c:423)
==21582== by 0x109166: main (main.cpp:4)
==21582==
==21582== LEAK SUMMARY:
==21582== definitely lost: 40 bytes in 1 blocks
==21582== indirectly lost: 0 bytes in 0 blocks
==21582== possibly lost: 0 bytes in 0 blocks
==21582== still reachable: 0 bytes in 0 blocks
==21582== suppressed: 0 bytes in 0 blocks
==21582==
==21582== For counts of detected and suppressed errors, rerun with: -v
==21582== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
==21582==
→ プロセス ID です。Invalid write of size 4
→ 無効なインデックス 10 arr[10] = 1
が指定されたことが検出されました。definitely lost
→ arr
を free (delete) していないことが検出されました。メモリブロックへの参照 ptr->ptr
は存在している場合であっても ptr
自体が lost してしまった場合は、結果として ptr->ptr
で参照するメモリブロックは利用できなくなります。このような場合のメモリリークは indirectly lost
として検出されます。
#include <iostream>
struct Node {
Node* ptr;
};
int main() {
Node* ptr = new Node();
ptr->ptr = new Node();
return 0;
}
出力例
$ valgrind --leak-check=yes a.out
==27212== Memcheck, a memory error detector
==27212== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==27212== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==27212== Command: a.out
==27212==
==27212==
==27212== HEAP SUMMARY:
==27212== in use at exit: 16 bytes in 2 blocks
==27212== total heap usage: 3 allocs, 1 frees, 72,720 bytes allocated
==27212==
==27212== 16 (8 direct, 8 indirect) bytes in 1 blocks are definitely lost in loss record 2 of 2
==27212== at 0x4835DEF: operator new(unsigned long) (vg_replace_malloc.c:334)
==27212== by 0x109166: main (main.cpp:8)
==27212==
==27212== LEAK SUMMARY:
==27212== definitely lost: 8 bytes in 1 blocks
==27212== indirectly lost: 8 bytes in 1 blocks
==27212== possibly lost: 0 bytes in 0 blocks
==27212== still reachable: 0 bytes in 0 blocks
==27212== suppressed: 0 bytes in 0 blocks
==27212==
==27212== For counts of detected and suppressed errors, rerun with: -v
==27212== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
プログラムが終了する前に free/delete されなかった領域が存在する場合に still reachable
と出力されます。プログラム自体が終了しているため definitely lost
の場合と異なりメモリリークとして問題になることはありません。
#include <iostream>
int main() {
int* arr = new int[10];
exit(1);
return 0;
}
出力例
$ valgrind --leak-check=yes a.out
==27963== Memcheck, a memory error detector
==27963== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==27963== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==27963== Command: a.out
==27963==
==27963==
==27963== HEAP SUMMARY:
==27963== in use at exit: 40 bytes in 1 blocks
==27963== total heap usage: 2 allocs, 1 frees, 72,744 bytes allocated
==27963==
==27963== LEAK SUMMARY:
==27963== definitely lost: 0 bytes in 0 blocks
==27963== indirectly lost: 0 bytes in 0 blocks
==27963== possibly lost: 0 bytes in 0 blocks
==27963== still reachable: 40 bytes in 1 blocks
==27963== suppressed: 0 bytes in 0 blocks
==27963== Reachable blocks (those to which a pointer was found) are not shown.
==27963== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==27963==
==27963== For counts of detected and suppressed errors, rerun with: -v
==27963== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)