ifstreamとreadのメモリリーク

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
ino-n

ifstreamとreadのメモリリーク

#1

投稿記事 by ino-n » 9年前

自分ではメモリ解放しているつもりなんですが,メモリがどんどん埋まっていきます.
どこが間違っているのでしょうか?
大雑把に書くと下のようなコードを書いてます.

void debug(char** filepath){
  ifstream fin;
  unsigned char* buf;
  for(int i=0;i<=100;i++){
    buf = new unsigned char[40000000];
   fin.open(filepath, ios::binary);
   fin.read((char*)buf,40000000);
   fin.close();
   delete [] buf;
  }
}

アバター
h2so5
副管理人
記事: 2212
登録日時: 14年前
住所: 東京
連絡を取る:

Re: ifstreamとreadのメモリリーク

#2

投稿記事 by h2so5 » 9年前

メモリの使用量はどのようにして計測していますか?

ino-n

Re: ifstreamとreadのメモリリーク

#3

投稿記事 by ino-n » 9年前

linuxなので,別窓のターミナル上で
$ free -s 1
として1秒ごとのメモリ使用状況を確認しています.
ちなみに下の例ではメモリリークは起こっていません.
どうも解放できてないのは配列のbufの方ではなく,ifstream finの方なのですが,
finもreadをしなければメモリが溜まっていくわけでは無いようです.

void debug(char** filepath){
  ifstream fin;
  unsigned char* buf;
  for(int i=0;i<=100;i++){
    buf = new unsigned char[40000000];
   fin.open(filepath, ios::binary);
   // fin.read((char*)buf,40000000);
   fin.close();
   for(int k=0;k<=40000000;k++)
     buf[k] = 255;
   delete [] buf;
  }
}

ino-n

Re: ifstreamとreadのメモリリーク

#4

投稿記事 by ino-n » 9年前

コードの貼り付け方を理解しておりませんでした.
同じコードを載せておきます.
ちなみにchar** filepathで送られてきているのはtif画像のアドレスです.

メモリ解放できていない

コード:

void debug(char** filepath){
  ifstream fin;
  unsigned char* buf;
  for(int i=0;i<=100;i++){
    buf = new unsigned char[40000000];
   fin.open(filepath[i], ios::binary);
   fin.read((char*)buf,40000000);
   fin.close();
   delete [] buf;
  }
}
メモリ解放できている

コード:

void debug(char** filepath){
  ifstream fin;
  unsigned char* buf;
  for(int i=0;i<=100;i++){
    buf = new unsigned char[40000000];
   fin.open(filepath[i], ios::binary);
   // fin.read((char*)buf,40000000);
   fin.close();
   for(int k=0;k<=40000000;k++)
     buf[k] = 255;
   delete [] buf;
  }
}

アバター
h2so5
副管理人
記事: 2212
登録日時: 14年前
住所: 東京
連絡を取る:

Re: ifstreamとreadのメモリリーク

#5

投稿記事 by h2so5 » 9年前

本当にリークしているかどうか怪しいのでvalgrindなどを使ってチェックしてみてください。

ino-n

Re: ifstreamとreadのメモリリーク

#6

投稿記事 by ino-n » 9年前

結果を書きます.
LEAK SUMMARYは出ませんでしたが,HEAP SUMMARYで
1,488 allocs, 1,488 frees, 3,000,989,266 bytes allocated
となっており,メモリ取得,解放数が同じなのに3GBもメモリを獲得したままになっています(という認識でいいのでしょうか?).
Conditional jump or move depends on uninitialised value(s)は
対象コードをコメントアウト化して消しても変わらなかったため省略しました.
いまいちこの結果の見方もよくわかっていないのですが,これはメモリリークではないのでしょうか?

コード:

$ valgrind --leak-check=full --leak-resolution=high --show-reachable=yes ./main -AM 100 config.txt
==11319== Memcheck, a memory error detector
==11319== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==11319== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==11319== Command: ./main -AM 100 config.txt
==11319== 

/* 中略 */

program will start with AM=100 and
config.txt
==11319== Syscall param open(filename) points to unaddressable byte(s)
==11319==    at 0x57430A0: __open_nocancel (syscall-template.S:81)
==11319==    by 0x56D1A47: _IO_file_fopen@@GLIBC_2.2.5 (fileops.c:228)
==11319==    by 0x56C5F23: __fopen_internal (iofopen.c:90)
==11319==    by 0x4EB2B5F: std::__basic_file<char>::open(char const*, std::_Ios_Openmode, int) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==11319==    by 0x4EEB039: std::basic_filebuf<char, std::char_traits<char> >::open(char const*, std::_Ios_Openmode) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==11319==    by 0x4EEC12F: std::basic_ifstream<char, std::char_traits<char> >::basic_ifstream(char const*, std::_Ios_Openmode) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==11319==    by 0x4042AB: debug(config&) (main.cpp:308)
==11319==    by 0x402840: main (main.cpp:54)
==11319==  Address 0x5a39c68 is 24 bytes inside a block of size 73 free'd
==11319==    at 0x4C2C2BC: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==11319==    by 0x4EF14DE: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==11319==    by 0x409C1B: IOsetting::filepath(int) (LoadConfig.cpp:110)
==11319==    by 0x404294: debug(config&) (main.cpp:308)
==11319==    by 0x402840: main (main.cpp:54)
==11319== 
==11319== 
==11319== HEAP SUMMARY:
==11319==     in use at exit: 0 bytes in 0 blocks
==11319==   total heap usage: 1,488 allocs, 1,488 frees, 3,000,989,266 bytes allocated
==11319== 
==11319== All heap blocks were freed -- no leaks are possible
==11319== 
==11319== For counts of detected and suppressed errors, rerun with: -v
==11319== Use --track-origins=yes to see where uninitialised values come from
==11319== ERROR SUMMARY: 4194 errors from 20 contexts (suppressed: 0 from 0)

アバター
h2so5
副管理人
記事: 2212
登録日時: 14年前
住所: 東京
連絡を取る:

Re: ifstreamとreadのメモリリーク

#7

投稿記事 by h2so5 » 9年前

リークはしていないようですね。最終的に確保しているサイズは in use at exit: 0 bytes in 0 blocks となっています。
3,000,989,266 bytes は total heap usage ですのでアロケートしたサイズの合計です。

ino-n

Re: ifstreamとreadのメモリリーク

#8

投稿記事 by ino-n » 9年前

リークではないのにプログラム終了後もメモリ解放されないということはあるのでしょうか?

コードを手直ししていたらエラーは全部とれてしまいました.

コード:

 valgrind --leak-check=full --leak-resolution=high --show-reachable=yes ./main -AM 0 config.txt
==2621== Memcheck, a memory error detector
==2621== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==2621== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==2621== Command: ./main -AM 0 config.txt
==2621== 

program will start with AM=0 and
config.txt
==2632== h-nozomu
==2632== HEAP SUMMARY:
==2632==     in use at exit: 0 bytes in 0 blocks
==2632==   total heap usage: 8,508 allocs, 8,508 frees, 20,419,180,105 bytes allocated
==2632== 
==2632== All heap blocks were freed -- no leaks are possible
==2632== 
==2632== For counts of detected and suppressed errors, rerun with: -v
==2632== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
プログラム実行前後のfreeコマンドの結果も貼ります.

コード:

ino-n% free                                                              [~]
             total       used       free     shared    buffers     cached
Mem:       7896288     869276    7027012      36020       1360     141076
-/+ buffers/cache:     726840    7169448
Swap:      8102908          0    8102908
ino-n% free                                                              [~]
             total       used       free     shared    buffers     cached
Mem:       7896288    7647444     248844      36952       8276    6687616
-/+ buffers/cache:     951552    6944736
Swap:      8102908          0    8102908
ino-n% 

アバター
h2so5
副管理人
記事: 2212
登録日時: 14年前
住所: 東京
連絡を取る:

Re: ifstreamとreadのメモリリーク

#9

投稿記事 by h2so5 » 9年前

Linuxトラブルシューティング探偵団 番外編(1):減り続けるメモリ残量! 果たしてその原因は!? (2/3) - @IT
 システムが利用可能なメモリ量を計算するには、Linuxのページキャッシュの扱いを理解する必要があります。LinuxはHDDなどのストレージに保存してあるデータの読み出し/書き出し時に確保したメモリをページキャッシュという形で保持します。

 CPU はストレージのデータを直接読むことはできません。そのため、ストレージデータはまずはメモリにロードする必要があります。Linuxでは、こうして読み込んだデータをページキャッシュとして再利用しています。いったん作成してしまえば、ページキャッシュは読み出し/書き出しにストレージを介さないため、非常に高速に動作します。

 ページキャッシュは新たなストレージデータの読み出し/書き出し要求などがあってメモリが必要とならない限り、メモリを解放しません。そのため、通常はシステムが稼働しているだけでMemFreeはページキャッシュとして活用されていき、ある程度までは減り続けます。

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: ifstreamとreadのメモリリーク

#10

投稿記事 by みけCAT » 9年前

ino-n さんが書きました:メモリ解放できている

コード:

void debug(char** filepath){
  ifstream fin;
  unsigned char* buf;
  for(int i=0;i<=100;i++){
    buf = new unsigned char[40000000];
   fin.open(filepath[i], ios::binary);
   // fin.read((char*)buf,40000000);
   fin.close();
   for(int k=0;k<=40000000;k++)
     buf[k] = 255;
   delete [] buf;
  }
}
配列の確保された領域の範囲外にアクセスしています。規格は知らないですが、危険な未定義動作かもしれません。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

閉鎖

“C言語何でも質問掲示板” へ戻る