web-dev-qa-db-ja.com

メモリリークC ++

文字列操作を行うC++でコードを書いたところですが、valgrindを実行すると、メモリリークが発生する可能性があります。コードを詳細レベルにデバッグする次のような単純なC++プログラムを作成しました。

#include<iostream>
#include<cstdlib>
using namespace std;
int main()
{
        std::string myname("Is there any leaks");
        exit(0);
}

valgrindを実行すると、次のようになります。

==20943== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 26 from 1)
==20943== malloc/free: in use at exit: 360,645 bytes in 12,854 blocks.
==20943== malloc/free: 65,451 allocs, 52,597 frees, 2,186,968 bytes allocated.
==20943== For counts of detected errors, rerun with: -v
==20943== searching for pointers to 12,854 not-freed blocks.
==20943== checked 424,628 bytes.
==20943== 
==20943== LEAK SUMMARY:
==20943==    definitely lost: 0 bytes in 0 blocks.
==20943==      possibly lost: 917 bytes in 6 blocks.
==20943==    still reachable: 359,728 bytes in 12,848 blocks.
==20943==         suppressed: 0 bytes in 0 blocks.
==20943== Reachable blocks (those to which a pointer was found) are not shown.
==20943== To see them, rerun with: --show-reachable=yes

それから、私たちが強制的に終了したことに気づきました(これは元のC++コードでも実行しました)。ここで問題となるのは、以前の古いコードが新しいコードの終了ステータスを待機しているため、プログラムを終了したいということです。たとえば、バイナリa.outは、b.outの終了ステータスを待ちます。メモリリークを回避する方法はありますか、またはプログラムがその時点ですでに終了しているため、メモリリークについて本当に心配する必要があります。

これはまた私にとって別の質問を提起します、そのようなコードは有害ですか?

#include<stdio.h>
#include<cstdlib>
int main()
{
        char *p=(char *)malloc(sizeof(char)*1000);
        exit(0);
}
45
Global Warrior

exit()の使用について主張の場合:

_#include<iostream>
int main(){
    {
        std::string myname("Are there any leaks?");
    }
    exit(0);
}
_

また、mainから戻ると、戻り値はアプリケーションの終了コードになります。したがって、終了コードを渡したい場合は、exitの代わりにmain()で_return exitCode;_を使用してください。

その部分について:

これはまた私にとって別の質問を提起します、そのようなコードは有害ですか?

はい、それは[〜#〜] bad [〜#〜]プログラミングの習慣だからです。

OSは、解放に失敗したメモリをすべてクリーンアップします。システムメモリとページファイルをすべて使い果たしていない限り、OSに損傷を与えることはありません。

ただし、ずさんな/漏れのあるコードを書くことは習慣になる可能性があるため、混乱をクリーンアップするためにOSに依存することは悪い考えです。

63
SigTerm

mainの最後にexit(0);の代わりにreturn 0;を使用します。 exitを使用すると、デストラクタの実行が回避されます。

65
swegi

これはまた私にとって別の質問を提起します、そのようなコードは有害ですか?

#include<stdio.h>
int main()
{
        char *p=(char *)malloc(sizeof(char)*1000);
        exit(0);
}

プロセスが終了すると、プロセスが所有するすべてのリソースが自動的に閉じられるため、最新のオペレーティングシステムでは害はありません。

ただし、それでも悪い習慣であり、数年のメンテナンスでコードがゆっくりと変化し、その日のうちに有害になるまで、微妙で見つけにくいエラーが発生する可能性があります。私は、コードの一部が10年前のものであるプロジェクトで働いており、そうすることでいくつかのレッスンを学びました。それらのいくつかはかなり厳しいものです。したがって、現在問題が発生していなくても、そのようなコードを書くことは避けたいと思います。

22
sbi

ほとんどの場合、すでに与えられている多くの正当な理由のために、自分の後でクリーンアップする価値があります:より良い保守性、チェックツールからのより良いユーティリティなど。

クリーンアップする他の機能上の理由がある場合、おそらくデータが永続ストアに保存されている場合、選択の余地はありません。クリーンアップする必要があります(ただし、設計を再検討することをお勧めします)。

ただし、場合によっては、終了して「リーク」した方がよい場合もあります。

プログラムの終了時に、プロセスは終了します。そうすると、オペレーティングシステムは、プログラムによって割り当てられたメモリを回復し、場合によっては、これをはるかに迅速に実行できます。

各ノードが動的に割り当てられ、実質的に動的に割り当てられた構造を持つ大きなリンクリストについて考えてみます。これをクリーンアップするには、各ノードにアクセスして各ペイロードを解放する必要があります(これにより、他の複雑な構造がウォークされる可能性があります)。

このような構造を実行するために、何百万ものメモリ操作を実行することになる可能性があります。

ユーザーはプログラムを終了したいと思っており、数十秒間そこに座って、大量のジャンク処理が行われるのを待ちます。彼らはおそらく結果に興味を持つことはできません-結局彼らはプログラムをやめています。

この「リーク」を許可すると、オペレーティングシステムは、プロセスに割り当てられたメモリのブロック全体をはるかに迅速に再利用できます。構造やオブジェクトのクリーンアップは関係ありません。

http://blogs.msdn.com/b/oldnewthing/archive/2012/01/05/10253268.aspx

最終的には、ツールが適切に使用されていることを確認するために、ツールが何を示しているかを理解する必要があります。

5
Rob

メモリリークを回避するには、mainを呼び出す代わりに、exitからステータスを返します。ゼロを返す場合は、必要に応じてreturnステートメントを省略できます。その場合、プログラムはゼロのステータスで終了します。

これはまた私にとって別の質問を提起します、そのようなコードは有害ですか?

最新のオペレーティングシステムでは、害を及ぼすことはありません。プログラムが終了すると、すべてのリソースが自動的に再利用されます。ただし、Valgrindなどのツールを使用して真の問題を見つけるのは難しくなるため、可能であれば、無害なメモリリークを回避することをお勧めします。

4
Mike Seymour
#include<iostream>
using namespace std;
int main()
{
    {
        std::string myname("Is there any leaks");
    }
    exit(0);
}
2
Peter Wood

実行を中断し、デストラクタを超えずにリターンコードを渡したい場合は、例外をスローし、main()で例外から戻り値を抽出します。

1
Rafał Rawicki

Main()が終了するときのように、プロセスが実際に終了するとき、OSはいずれかの方法でアプリケーションに割り当てられたすべてのリソースを再利用します。どのように終了するかはそれほど重要ではありません-少なくとも動的メモリに関しては。

分散データベース接続を開いている場合などは、atexit()ハンドラーを使用して閉じる必要があります。ストレートアップ出口で強制終了すると、それらが実行されなくなる可能性があります。これは悪いことですが、OSリソースに関する限りは'おそらく大丈夫です。

また、プロセスの終了によってファイルロックが解除されない可能性があるため、(手動の)ファイルロックなどを必ず解除する必要があります。

別の意見を追加します。

そのようなコードはすべて有害ではありません。プロセスが終了すると、OSがすべてを処理します。それ以外の場合は、OSが不安定になります。永続データ(ファイルなど)に一貫性があることを確認してください。

もう少し挑発的に述べると、プログラムの終了時に明示的にメモリを解放することは有害な場合があります。

  1. プログラムの終了に時間がかかる(コンピューターがシャットダウンするまでプログラムが終了するのを待つのにイライラしたことはありませんか?)
  2. 特にサードパーティのコンポーネントでは、破壊の正しい順序は必ずしも簡単ではありません(終了時にクラッシュする可能性のあるいくつかのプログラムを覚えています)
  3. OSはメモリを解放できない場合がありますmain(*)を離れた後、代わりにプログラムを強制終了します

Valgrindに特定の出力を提供させるためだけに、これを危険にさらしますか?(**)


(*)

#include<iostream>
using namespace std;
std::string myname("Is there any leaks");
int main() {
        exit(0);
}

(**)もちろん、メモリアナライザの出力は、「ノイズ」がない方が便利です。デバッグモードの終了時に明示的にメモリを解放するだけではどうでしょうか?

0
Meinersbur

プログラムが終了している場合は、mallocまたはnewで割り当てられたメモリについて心配する必要はありません。 OSがそれを処理します。プロセスが終了すると、プロセスの仮想アドレス空間内のすべてのものが排他的に消えます。共有メモリまたは名前付きパイプを使用している場合でも、問題になる可能性があります。

0
Borealid