こんにちわ。
前回は大変お世話になりました、クロウです。
boost::asioの方は実装できまして、次にファイルのアーカイブ化に着手したのですが、アーカイブ化したファイル読み込み時にメモリリークが発生して困っています。
〜Main〜
CArchiveLoader* Archive;
Archive=new CArchiveLoader();
Archive->Load("imgdat.dat");
〜Archive〜
bool CArchiveLoader::Load(string name)
{
DWORD nbytes;
HANDLE h=CreateFile(
name.c_str(), GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (h==INVALID_HANDLE_VALUE) return false;
DWORD size=GetFileSize(h, NULL);
char* data=new char[size];
if (WorkSize<size)
{
if (Work) delete[] Work;
Work=new char[size];
WorkSize=size;
}
ReadFile(h, Work, size, &nbytes, NULL);
CloseHandle(h);
Rand.Init(Password);
for (DWORD i=0, n=size-3; i<n; i+=4)
{
*(DWORD*)(Work+i)^=Rand.Int32();
}
DWORD sum=0;
for (DWORD i=4, n=size-3; i<n; i+=4)
{
sum+=*(DWORD*)(Work+i);
}
if (sum!=*(DWORD*)Work) return false;
Entry.clear();
char* p=Work+sizeof(DWORD);
DWORD num_entries=*(DWORD*)p;
p+=sizeof(DWORD);
for (DWORD i=0; i<num_entries; i++)
{
ARCHIVE_ENTRY e;
e.Name=p;
p+=e.Name.length()+1;
e.Size=*(DWORD*)p;
p+=sizeof(DWORD);
e.Offset=*(DWORD*)p;
p+=sizeof(DWORD);
e.Data=Work+e.Offset;
Entry.push_back(e);
}
return true;
}
〜エラーメッセージ〜
Detected memory leaks!
Dumping objects ->
{767} normal block at 0x00A76EC8, 32 bytes long.
Data: <imgdat\ yL.png> 61 69 6D 67 5C 97 EC 96 B2 8A 79 4C 2E 70 6E 67
{765} normal block at 0x00A75F08, 32 bytes long.
Data: <imgdat\ {L.png> 61 69 6D 67 5C 97 EC 96 B2 93 7B 4C 2E 70 6E 67
{763} normal block at 0x00A75EA8, 32 bytes long.
Data: <imgdat\ L.png> 61 69 6D 67 5C 97 EC 96 B2 8A EC 4C 2E 70 6E 67
〜〜〜
多分どこか妙な所でメモリリークしているのだと思うのですが、どうすればいいのかわかりません。
イマイチどうすればよいのかわからないので、わかる方がいらっしゃればお願いします。
ソース読む気になれないのでぱっと見で。
new[] してるのに delete[] してないのが原因。
きっちり delete[] しておくんなまし。
ないしは new/delete せずに vector<char> 等に直すもよし。
でもさー
無節操にファイルの全データをメモリに読んでるっぽいけど
DVD-R ISO Image みたいな巨大ファイルが指定されたらとか、考えてある?
その後変更してみましたが、状況的には変わりません。
〜〜
char* data=new char[size];
if (WorkSize<size)
{
if (Work) delete[] Work;
Work=new char[size];
WorkSize=size;
}
ReadFile(h, Work, size, &nbytes, NULL);
delete [] data;
〜〜
この部分ではメモリリークは発生していないようなので、多分原因は別の箇所かなと思っているのですが……。
ほかのところだと思うんなら、この部分挙げてもしょうがないじゃん・・・
new と delete は常にペアで存在するべき。
new CArchiveLoader したのを delete してるかどうかチェック。
っていうか Work にせよ CArchiveLoader にせよ new する必要があるの?
単純に局所変数にすれば delete 忘れもなくなってよいはずだが。
普通に MFC の CArchive を使う際には局所変数にして使う。
CArchive を new/delete するコードなんか見たことないよ。
CArchiveLoader と CArchive は違うんだろうけどさ・・
Workとdataの2種類を new[]してますが
Workはdelete[]してないですね
Workを使う前に前回のメモリを確認してるようだけど
・WorkがLoaderクラスのメンバ変数なら毎回新しいので前回のを消せない
・グローバルとかなら、アプリを終了させるときにちゃんと消しているか?
あと、dataって使ってないような・・・
rinさん、tetrapodさん>ありがとうございます。
取り合えず、自分でvector<char>Work(size)にしてみたのですが、今度はメモリリークではなく読み込み中にアクセス違反が発生しました。
後、CArchiveをヘッダ部分でCArchiveLoaderにしているので基本的にはCArchiveです。
〜ヘッダ部分〜
class CArchiveLoader : public CArchive {
protected:
char* Work;
DWORD WorkSize;
public:
CArchiveLoader();
~CArchiveLoader();
bool Load(string name);
};
〜〜
ARCHIVE_ENTRY などはあまり見かけないワードですが
継承元クラスのCArchiveはMFCのCArchiveですか?
ARCHIVE_ENTRY をMSDNで検索したり
ARCHIVE_ENTRYとCArchiveを合わせてグーグルで検索しても
うまくひっかからないので・・・
CArchiveはMFCの物です。
ARCHIVE_ENTRYやEntryはMFCのCArchive関連には無いようですが・・・?
〜〜
struct ARCHIVE_ENTRY {
string Name;
DWORD Size, Offset;
char* Data;
};
〜〜
……となってましたです。
ツイート | ![]() |