C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

std::vectorのメモリ解放について教えてください

[トピック内 5 記事 (1 - 5 表示)]  << 0 >>

■95206 / inTopicNo.1)  std::vectorのメモリ解放について教えてください
  
□投稿者/ sw (1回)-(2020/07/01(Wed) 15:09:43)

分類:[C/C++] 

Visual Studio 2010を使ってC/C++のアプリケーションを開発しています。
前任者のソースコードを引き継いでいるのですが
std::vectorが使われている箇所が多々あります。
C++のSTLのことがわかる方、教えていただけないでしょうか。

(1)std::vertor型変数を使用したあと、必ずclear()を使って明示的に解放しなければならないのでしょうか?
 現在、アプリケーション全体でメモリリークが疑われる挙動があり、処理を追っているとstd::vertor型変数を使用した後処理がなされていないものがありました。
 明示的に解放する必要があるとすれば、これがメモリリークの原因なのではないかと疑っています。

(2)Webサイトで調べると、clear()だけでは不十分とのことで以下のようなswap処理を入れて解放しているところがあります。
 これはすべてのstd::vectorを使ったコードにあてはまる話なのでしょうか?
  std::vector<int> vec;
  std::vector<int>().swap(vec);

(3)以下のWebサイトを見る限りでは、swapによる解放は1件しかされていないようです。
全て解放するためには、vectorの要素数分行う必要があるという認識よいのでしょうか?
https://seesaawiki.jp/asama-yaya/d/std%3A%3Avector%A4%CE%A5%E1%A5%E2%A5%EA%B3%AB%CA%FC%A4%CB%A4%C4%A4%A4%A4%C6



引用返信 編集キー/
■95208 / inTopicNo.2)  Re[1]: std::vectorのメモリ解放について教えてください
□投稿者/ 774RR (803回)-(2020/07/01(Wed) 15:42:45)
2020/07/01(Wed) 15:50:58 編集(投稿者)
2020/07/01(Wed) 15:50:44 編集(投稿者)

オイラが思うに何をもって「メモリ消費量」を計測しているかで話は違うっす。
タスクマネージャのメモリ消費量をもってリークを判断しているとしたら、それは判断基準自体が誤り。
vector に限らず「メモリを解放」してもタスクマネージャのメモリ消費量は減らないことがある。

その辺が問題なく理解できているというなら下記を読む価値はあって

vector::size() と vector::capacity() の違いは理解してる?
世間一般的にいうメモリ消費量は capacity() のほう。
なので「メモリの解放」は capacity() を減らすことを言うっす。

(1-1) std::vector も寿命が尽きれば要素用のメモリとともに消去されるので

void func1(size_t n) {
    std::vector<int> v(n);
    ...
}
別の関数がこの func() を呼び出して、呼び出し元に帰ってきたときにはメモリは解放されてる。
# 専門用語で「デストラクトされる」という

(1-2) std::vector 自体を new してるんなら delete が必要

void myclass_t::func2(size_t n) {
    this->m_v = new std::vector<int>(n);
}
要するに class myclass_t { std::vector<int>* m_v; } であることを想定。
そうなら、この m_v はどこかで delete m_v; が必要で、なければリーク。
(オイラはこの書き方を推奨しない)

(2) vector::clear() では vector::capacity() は変化しないので「消費メモリ」は減らない仕様
つまりありとあらゆる vector で同じ挙動

int main() {
    std::vector<int> v(100);
    std::cout << v.size() << ':' << v.capacity() << std::endl;
    v.clear();
    std::cout << v.size() << ':' << v.capacity() << std::endl;
}


(3) vector の保持している全要素用のメモリがなくなるっす。
ただし、これが本当に必要か? と問われればまず 99% のケースでは不要。
C++11 以後なら vector::shrink_to_fit() のほうがわかりやすいっす。
https://cpprefjp.github.io/reference/vector/vector/shrink_to_fit.html

「本当にリークしているのか」今までの検証結果の妥当性の検証から。

引用返信 編集キー/
■95215 / inTopicNo.3)  Re[2]: std::vectorのメモリ解放について教えてください
□投稿者/ ぶなっぷ (227回)-(2020/07/02(Thu) 11:17:43)
メモリリークって、考え方により、いろいろあると思うんだ。
「アプリケーション終了時に1つでも未開放の領域が残っていること」
だとするなら、C++にはメモリリークはあるけど、C#にはないことになる。
だって、ガベージコレクトだからね。

でもね、C#にもメモリリークはある。
たとえば、リアルタイムにネットのパケット数をモニタするようなアプリだとする。
グラフ化して表示するには、パケット数をバッファにため込む必要があるけど、
このバッファを開放するコードが存在しなければ、いつかはバッファ領域がメモリを
使い果たすよね。
これってメモリリークって言っちゃっていいよね。
でも、C#だからアプリさえ終了させれば、そのときにはちゃんとガベージコレクト
される。

こういうタイプのメモリリークなら、いくらちゃんとclear()を呼んでても、
そのタイミング次第でメモリリークしちゃうわけだ。

話の内容から察するに、タイミングについても、きちんと調査したほうが良いと
思われるよ(^^)

引用返信 編集キー/
■95248 / inTopicNo.4)  Re[3]: std::vectorのメモリ解放について教えてください
□投稿者/ sw (2回)-(2020/07/03(Fri) 14:42:57)
メモリ計測ですが、OS(Windows 10)のパフォーマンスモニターを使用して計測しています。
計測対象は、XXX.exeのPrivate Bytesです。
この数値が右肩上がりとなっているため、メモリリークを疑っています。

vector::size() と vector::capacity() の違いは分かっていませんでした
何日も連続で動かすソフトウェアのため、vector::capacity()がどれぐらい増加するのかを調べてみたいと思います。

引用返信 編集キー/
■95250 / inTopicNo.5)  Re[4]: std::vectorのメモリ解放について教えてください
□投稿者/ 774RR (804回)-(2020/07/03(Fri) 15:35:52)
Windows10 のリソースモニターの場合

・コミット=そのプロセスが OS から借りているメモリ量
 アクティブに使っているものは物理メモリに残り、使用頻度の低いものはスワップアウトされるが
 その両者を合わせた値。
 「メモリリーク」したら、リークした領域は通常アクセスされない(その手段が無い)ので
 コミット量が増えていき、下記(プライベート)ワーキングセットが増えないのが普通。

・ワーキングセット=物理メモリの使用量、他プロセスと共有できるもの
 コミット<ワーキングセットになることはおかしくない

・プライベートワーキングセット=物理メモリの使用量、他プロセスと共有してないもの
 コミット>プライベートワーキングセットになるのが普通

なのでコミットのほうもチェックしたらいいっス。
コミットが増え続けているならほぼ確実にメモリリーク。
コミットが増えずにプライベートワーキングセットだけ増え続けてるなら別原因かも。

std::vector も malloc() も、「連続した仮想記憶アドレス空間」が必要である仕様なので、
仮想記憶空間の断片化ってやつが起こると「空きがあっても使えない」ことに注意。

引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ