• 締切済み

C言語で、メモリを解放しないで終わるプログラム

C言語の話です。 mallocなどで領域を確保したら、解放しなければいけないんですよね。 しかし、解放しないで終了すると具体的にどうなるのか、私は理解していません。 次のような、freeしないプログラムを作って何回か実行してみました。しかし、別におかしくならないですね。 #include <stdio.h> #include <string.h> #include <stdlib.h> char *cp; int main(void) { unsigned int n; printf("サイズ(2以上)を入力してください:"); scanf("%d",&n); cp=malloc(n); if(!cp) { printf("%s\n","mallocできませんでした。"); return(1); } strcpy(cp,"A"); printf("cpは%sです。\n", cp); printf("それでは終わりにします\n"); return(0); } グローバルでcharの固定長の配列を宣言したとすれば、プログラムの終了時にその領域は解放されると思います。 このような固定長の配列の場合とmallocの場合との違いが問題なんです。  実験的に、解放しないがために何かおかしくなってしまったり、悪影響を及ぼしたりするようなプログラムを作りたいんですが、どのようにすればよいでしょうか。 もしも私の環境ではそのようなプログラムが作れないなら、別の環境の話でもよいので具体的にこんなふうになってしまうという話をお聞きしたいんです。 過去の質問を検索してみました。 http://oshiete1.goo.ne.jp/kotaeru.php3?q=160037 ここのNo.9では、「freeしないアプリケーションの起動・終了を繰り返すと、リソースが不足する」旨が書かれていて、質問者の方もそれで納得されているようです。 しかし、私は、リソースが不足するとはどういうことで、何が起こるのか、知りません。 私のマシン OS:Windows98SE VC++6.0

noname#2004
noname#2004

みんなの回答

noname#2009
noname#2009
回答No.10

>C言語でのANSI規格やK&Rによる「Programing >C」においても「アロケートしたメモリはfreeすること >で開放する」となっています。本書もこれらと同じ立場 >です。 > >(3)で言っているのは、「freeすることで解放する >んだ。プログラムが終了することで解放するなんてい >うことは規格にはないぞ。」ということでしょう。 ・「K&R」は書式の規格であり動作を表すものでは  ありません。 ・C言語のメモリ管理はプログラム動作中の話であり、  終了後の処理を規定するものではありません。 ・メモリリークはOSの問題です。 わからんことは自分で書いてね。別に誰も困らないから。

  • toysmith
  • ベストアンサー率37% (570/1525)
回答No.9

> mallocによってOSから借りたメモリは、 > 必要がなくなった時点でfreeにより、 > OSに返すのが、C言語でのルールです この表現は明らかな間違いを含んでいます。 ・freeはOSに領域を返却しない マンションの例えを続けます。 マンションが満杯のときに新しい入居者があった場合、mallocはマンション自体を建て増しするようなカンジで未割り当て領域自体を拡張するような実装は存在します。 このとき、OSに新しい領域を要求するか否かは実装依存です。 しかし、freeは「未入居」とマークをつけて新たな入居者の受け入れ準備をするだけで、マンションの取り壊しは行いません。 そんなことをするとmalloc/freeの連続によってシステムに強烈な負担を強いることになります。 (仮想記憶システムではページングが発生するため、システム全体の運用が中断する可能性がある) ・そもそもmallocがOSから領域を借用している保証は無い mallocがOSから領域を借用するかどうかは実装依存です。 通常はアプリケーション領域のヒープ領域から割り当てが行われるので、mallocがOSに働きかけるような実装はほとんど存在しません。 mallocがシステムコール扱いであるようなシステムならありえることですが、C言語のライブラリに依存するようなシステムコール体系のOSなんて存在しないでしょう。 WindowsのGlobalAllocのようなシステム依存のメモリ割り当て関数ならOSに働きかける可能性があります。 ・「C言語のルール」が意味不明 C言語の体系は多岐にわたりますが、初代のC(UNIX上のRitchie-C)および2代目のC(いわゆるUNIX-CであるJhonson-C)ではここでいう“ルール"は通用しません。 (UNIXと言うOSがmallocをシステムコール扱いしていないため) また、ANSI-C/Hosted Environmentでは先に書いた理由でOSからのメモリ割り当ての可能性はほとんどありません。 ANSI-C/Free Standing EnvironmetにおいてはOSの存在を想定していないので、全く当てはまりません。 WhiteSmith-Cなどの(現在では駆逐されてしまった)方言色の強い実装ではありえる話ですが、1989年以降はルールと呼べるほど一般的ではありません。 ANSI-Cと一口に言ってもHosted EnvironmentとFree Standig Environmentでは全く違った構成になります。

noname#2004
質問者

お礼

(補足の後のお礼 7月13日) 『C言語 ポインタが理解できない理由』について、出版社に質問したら、答えが返ってきました。 出版社からの答えの文言そのままではないですが、ほぼ次のような内容の答えでした。 「ご質問頂いた項目に関して、以下に回答致しますので、ご査収ください。 (1)freeによりOSに返すのか返さないのかという点について、本書では相反する内容が書かれている  --基本的には、アロケートしたメモリはfreeするべきというのが、本書の意見です。freeの動作は正確には、動作環境に基づく内部的な都合により、即座にメモリをOSに返しているわけではありません。しかし、以下の(3)にも関係しますが、本書では、アロケートしたメモリを利用終了後に開放する(=最終的にOS管理下に戻す)という立場ですので、freeするように記述しています。 (2)プログラム終了直前のfreeは必要か?  --人によっては必要がないという指摘もありますが、本書では(1)、(3)と関係していますが、freeが必要と考えています。 自分でアロケートしたメモリの責任を最後まで考慮するという考えです。 (3)「C言語でのルール」とは?  --C言語でのANSI規格やK&Rによる「Programing C」においても「アロケートしたメモリはfreeすることで開放する」となっています。本書もこれらと同じ立場です。 以上 」 (3)で言っているのは、「freeすることで解放するんだ。プログラムが終了することで解放するなんていうことは規格にはないぞ。」ということでしょう。 ということは、この本が言っていることは、 「現実のOSでは都合や理由があって、freeしてもすぐにはOSに返されるわけではない。またプログラムが終了すれば自動的に解放される。しかし、ルールとしては必ずfreeしなければならない。プログラムが終了する直前であっても解放しなければならない。もし、プログラムが終了しても解放されないような処理系があったとしても規格には反しない。」 ということなんでしょう。「プログラムが終了したら解放されると規格で定まっているが、他方、ルールはルールとしてプログラム終了直前でもfreeしなければならない」という立場では ない ようです。それだったらtoysmithさまのNo.6の回答どおり、まったくムダですからね。 本の立場はわかりましたし、プログラムが終了する直前にfreeする必要はない、という立場もわかりました。  どちらが正しいかの判断は私にはできません。  新たなご回答がなければ、数日で締め切りたいと思います。   私としては、toysmithさまのNo.6が一番わかりやすくて、良かったと思います。 >ANSI-Cと一口に言ってもHosted EnvironmentとFree Standig Environmentでは全く違った構成になります。 私は「規格」とかANSI-Cと何度も書きますが、よく考えるとそれらの中身をわかっていないようです。よく勉強したいと思います。

noname#2004
質問者

補足

 ご回答ありがとうございます。 ご回答で問題になっている本『C言語ポインタが理解できない理由』(浅井淳 著、技術評論社)の記述を読み進めていくと、「freeすると本当にメモリはOSに返されるのか?」という節があり、次のようなことが書いてあります。 -----------------------------------  mallocにより取得されるアドレスは、データセグメント内のヒープと呼ばれる領域にある。ヒープは、mallocするたびにスタックの方向に拡張されていく。しかし、freeを行なってメモリを解放しても、ヒープ全体が縮小するわけではない。  では、なぜfreeを行う必要があるのだろうか。freeすることで、ヒープが拡張するのを食い止める働きがある。mallocの内部では、freeされて未使用となった領域があるのなら、その領域を返す。つまりメモリのリサイクルを行う。つまり、free直後は空きメモリになるが、OSには返されず、しばらくはそのままヒープ上に残っている。 ----------------------------------- 私としては最後の「しばらくは」というのも気になりますがそれはともかくとして、どうも著者は、「freeしたからといってメモリはOSは返されませんよ。」ということを言っているんだと思います。これはtoysmithさまのご回答と符合するので、正しいんだと思います。  しかし、回答No.5の補足で書いたとおり、この本では少し前の方で 「freeを行わなくても、プログラムが終了すれば、自動的に空きメモリになります。といっても、プログラマがfreeを行わなくても良い、ということではありません。mallocによってOSから借りたメモリは、必要がなくなった時点でfreeにより、OSに返すのが、C言語でのルールです。」 と書いてあります。  著者は、自分自身が書いた、この「freeによりOSに返す」という記述を否定しているのです。  そうすると、疑問になってくるのは、著者は、本当は「プログラムが終了する直前にはfreeする必要はない」と思っているのではないだろうか、ということです。それとも著者は、「freeしてもOSに返されないが、ルールはルールとして守らなければいけない。だから、終了直前でもfreeしなければならない」という意見だろうか、とも考えられます。 (ご回答より) >・「C言語のルール」が意味不明 そうですね。 「C言語でのルール」が何かという点も含めて、この本のfreeの記述については、疑問が湧いてきます。  もうあんまり気にしないようにしようかとも思いました。  しかし、この本の最後に、本の内容に関して質問を受け付ける旨が書いてあるので、せっかくなので出版社に質問してみよう、と思いました。

noname#2009
noname#2009
回答No.8

欠けている2つ目URL といってもたいしたモンではないが

参考URL:
http://www.geocities.co.jp/HeartLand-Namiki/8971/win/risousu.htm
noname#2004
質問者

お礼

参考URLのほう、よく読んでみます。

noname#2009
noname#2009
回答No.7

>「質問のソースで、多くのサイズをmallocさせれば、OSが >フリーズする」とおっしゃっていますか? >それとも、 >「質問のソースでは、たとえどれだけ多くのサイズをmallocしても、 >OSのフリーズは起きない。」とおっしゃっていますか? あなたは、まずどちらだと思いますか。 回答では、前半部分では容量の話、後半部分では開放タイミングの話を しています。『多くのサイズ』かつ『終了させないこと』がそのソースで リークを確認する条件です。 そもそも答えはひとつしかありません。 そこまで追求ができるのであれば、既にある程度理解なさっていると 思われます。把握できた時点で『よし』としてもらいたいんですけど・・・ では順番に >「mallocしてfreeせずにプロセスが終了す ~ 反応しなくなってしまう。」 プロセス終了時には解放されます。プロセス終了時にも解放されないのは リソースリークです。 >リソースメータというのは、どこにありますか? Win98 ならスタートメニューから「プログラム」「アクセサリー」 「システムツール」「リソースメータ」にあります。なければCD-ROM からインストールして下さい >この話はアプリが終了しないで継続して実行するときの話ですよね。 メモリリークの注意とはそもそもそういう状況の話で行います。 main() 関数ひとつだけのアプリケーションでは質問に対する回答を 話していくのが難しいのです。 >リソースリークというものはどのようにすれば起きるのでしょうか。 >どのようなソースならばそれが起きるのでしょうか。 私は、あなたが検索した過去の質問のどの部分に納得いっていないのかを 知らないのです。ひとことで『どのようなソース』と言っても、あなたの 現在の知識範囲がわからないので答えようがないのです。一応書くだけ 書きます。 Windowsプログラミングでは Win32API というものを使います。その際 リソースハンドルという概念であらゆるOS資源にアクセスします。 そして使用後解放を行います。 例えばビットマップを利用するときには HBITMAP hBmp = CreateBitmap( ・・・ ); ~ DeleteObject(hBmp); のようにコーディングしますが、このときの DeleteObject() を行わないと ・ハンドル(個数) ・使用メモリ の2つがリークします。これらはOS上の全システム共通に一意管理されて いるので再起動するまで取り戻すことは不可能です。 その他 参考URLもどうぞ ・・・・・・・・・ 一応メモリリークソースです。見たままです。 int main() { char* p; while(1) p = malloc(3000000); return 0; } 最後に・・・ 何を欲しているのかがいまひとつピンときません。『解放できないと 具体的に何が起こるのか』という質問だったと思うのですが。 どうも禅問答の類は苦手です。とんちの利くような機転は持ち合わせて いませんので。。

参考URL:
http://www.dj.st44.arena.ne.jp/xwin2/mainhtml/win/sysresource00.html,http://www.geocities.co.jp/HeartLand-Namiki/8971/wi
noname#2004
質問者

お礼

ありがとうございます。

  • toysmith
  • ベストアンサー率37% (570/1525)
回答No.6

書き忘れましたのでもう一度。 malloc/freeを1セットで考えている人がいるようですが、「プログラム終了時にすべてをfreeする」なんていう処理は愚の骨頂です。 malloc/freeはマンションの内装工事のようなものです。 mallocは次の入居者のために内装工事を行います。 freeは次の入居者のための回復工事です。 マンション自体の取り壊し(=プログラムの終了)が行われる寸前に回復工事の必要はありません。 動的メモリ領域を10000個くらい確保して、freeして終了する場合とfreeせずに終了する場合を比べてみてください。 プログラム終了寸前にfreeするのは無駄以外の何者でもありません。

noname#2004
質問者

お礼

このマンションのたとえくらい優しく説明されると、よくわかります。

  • toysmith
  • ベストアンサー率37% (570/1525)
回答No.5

ANSI-C規格の範囲で考えます。 よって、ここでいう「動的メモリ」はmalloc,realloc,callocで確保されたものに限定されます。 ANSI-C準拠の処理系ではプログラム終了時に動的確保されたメモリ領域はすべて開放されなければなりません。 これは、プログラムの終了方法(main関数でのリターン、任意の場所でのexitなど)にかかわらず必ず開放されなければなりません。 たとえ、強制終了であっても何らかの方法で動的メモリが開放されることが前提です。 よって、動的にメモリを確保してままプログラムが終了しても何の問題も起こりません。 問題が起こるのはむしろ「プログラムが終了しない場合」です。 サーバーソフトウェアなど、プログラムが終了しないまま連続稼動していると確保され続ける動的メモリ領域は膨大な量になり、最終的にはメモリ不足を引き起こします。 また、仮想記憶システムではスワップシステム(ページ管理テーブルやディスク上のスワップ領域自身)を圧迫します。 Windows特有のリソースの圧迫を心配されているようですが、Windowsの一般的な処理系におけるANSI-Cの動的メモリ確保関数はWindowsのユーザリソース、GDIリソースを消費しません。 よって、malloc/freeの呼び出しとリソースの不足は何の関連ももちません。 そもそも、mallocがOSからメモリを提供されている保証はなく(mallocの実装方法は処理系依存のため)、たとえmallocがOSから領域を提供されていてもfreeがOSに返却することはほぼありません。 freeは「再利用できるようにする」という関数であり、返却はfreeの機能範囲に含まれません。 メモリ領域をOSに返却するのはプログラム終了時だけです。 よって、freeのある/なしは終了したプログラムのメモリリークに関連することはありえません。 多分、APIなどANSI-C標準関数以外の動的メモリ操作関数と混同されているのではないでしょうか?

noname#2004
質問者

補足

>ANSI-C規格の範囲で考えます。 >よって、ここでいう「動的メモリ」はmalloc,realloc,callocで確保されたものに限定されます。 そうですね。私の場合、この質問の問題は、範囲を限定して考えたほうがよさそうです。 > >ANSI-C準拠の処理系ではプログラム終了時に動的確保されたメモリ領域はすべて開放されなければなりません。 >よって、動的にメモリを確保してままプログラムが終了しても何の問題も起こりません。 ANSI-C準拠の処理系では、プログラムが終了すればすべて解放されるんですね。 「動的メモリ」をmalloc,realloc,callocで確保されたものに限定しても、 この問題については、本によって微妙に異なる説明をしていることがわかりました。 単に「mallocで確保した領域は、プログラムが終了したときには自動的に解放される。」とした本もあります。 別の本にはこう書いてあります。 「mallocしたメモリ領域をfreeすることなく、放置しておくとどうなるでしょう。プログラムが終了する際に、OSはプログラムが使っていたメモリ領域をすべて開放します。そのため、freeを行わなくても、プログラムが終了すれば、自動的に空きメモリになります。といっても、プログラマがfreeを行わなくても良い、ということではありません。mallocによってOSから借りたメモリは、必要がなくなった時点でfreeにより、OSに返すのが、C言語でのルールです。」(『C言語ポインタが理解できない理由』) ここでいう「C言語でのルール」というのがANSI-Cかどうかわかりません。 また他の本では 「現状で、PCなどで普通に使われているオペレーティングシステムなら、プロセス終了時に、そのプロセスが確保していた領域は、確実に解放してくれます。  もっとも、それは、Cの規格で規定されているわけではないのですが、まともなOSならまず大丈夫です。」(『C言語ポインタ完全制覇』) これらの本で言いたいことは、 「現実に世の中で広まって使われているようなOSではプログラム終了時に解放しているが、それはC言語の規格で決まっていることではないので、C言語で処理系に依存しないように正しくプログラミングするときには、終了時に解放すべきだ」 ということだろうと思います。 ANSI-C準拠ならば終了時に解放するといえるのか、と追究したい気持ちもあるんですが、あまり実益がなさそうなので、やめます。

noname#11476
noname#11476
回答No.4

お答えは、No.1, No.2の方の答えのとおりですが、多分リソース不足の意味もご存知ないとのことなのでわかりやすく翻訳しましょう。 1.メモリ、リソースメモリ a)メモリにはデータ領域、プログラム領域として割り当てられるメモリ(mallocwで割り当てられる)と b)主にウィンドウ表示、その他プログラム側より主にOSにお願いする仕事をやり取りする特別なメモリ領域であるリソースメモリ がプログラムを組むときに必要になります。 2.メモリの習得、解放 mallocで割り当てられたメモリは通常アプリケーションでfreeされますが、もししなかった場合でも、そのアプリケーション自体が終了するときにOSが解放します。 例外はNo.2の方が言われたようなOS自身が使っているとか、ほかのプログラムと共有しているメモリの場合などですね。 つまり、通常は問題が起きません。しかし、たとえばほかのアプリケーションから子供のプロセスとして起動するなどの場合は要注意です。 なので、知らない間に問題が発生しているということになります。 3.リソースメモリ こちらはより厄介です。これは明示的に解放してあげないと、プログラムが終了しても解放してくれません。 たとえば、プログラムでWindowを沢山作って表示して、でもちゃんと解放せずに終了してしまうような作りとか、前のリソースメモリを解放せずにポインタに新しいリソースメモリを割り当ててしまうなどしてしまうと、それがそのまま残ってしまいます。 一般にこのような解放されずに使われないメモリ領域が発生することをメモリリークと呼んでいます。 安定なシステムを構築する場合には深刻な問題になります。 Windows98が長期間安定に動作を続けられないのも、このメモリリークに弱いからです。 Windows2000, XP などはそもそもリソースメモリが豊富にあるので、まだ安定性は高いのですが。 リソースメモリの量はアクセサリの中にリソースメータというプログラムがありますので、それで見ることができます。 リソースメモリが不足した場合は、システム全体が不安定になります。 どうなるのか試したければ、Windows9x, Me で少々重いソフトを次々と立ち上げてみてください。多分メモリリソース不足という警告を見ることができます。

noname#2004
質問者

補足

>2.メモリの習得、解放 >mallocで割り当てられたメモリは通常アプリケーションでfreeされますが、もししなかった場合でも、そのアプリケーション自体が終了するときにOSが解放します。 だから、質問のプログラムは問題が起きないわけですね。 >つまり、通常は問題が起きません。しかし、たとえばほかのアプリケーションから子供のプロセスとして起動するなどの場合は要注意です。 >なので、知らない間に問題が発生しているということになります。 本当は、 子供のプロセスとして起動するとはどういうことか、 なぜその場合は「要注意」なのか、 などと突っ込んで考えてみたいところですが、 私の知識では、いろいろ調べたり説明をいただいてもわからないと思いますので、やめておきます。 >3.リソースメモリ >こちらはより厄介です。これは明示的に解放してあげないと、プログラムが終了しても解放してくれません。 なるほど、リソースメモリの場合は、「OSが自動的に解放する」とはならないんですね。 >一般にこのような解放されずに使われないメモリ領域が発生することをメモリリークと呼んでいます。 「メモリリーク」という言葉はふつうそういう意味のようです(本にもそう書いてあります。)が、今手元にある『C言語ポインタが理解できない理由』(浅井淳 著)という本では微妙に違うニュアンスで説明されています。 「mallocで獲得したメモリ領域が、プログラムのどこからも参照できなくなってしまった状況をメモリ・リークと呼びます。メモリ・リークは、ポインタのハンドリングを誤ると簡単に起こります。」 使い方は違うが、結局は使わないメモリ領域が解放されずに残るんですから同じことなんでしょう。 >リソースメモリの量はアクセサリの中にリソースメータというプログラムがありますので、それで見ることができます。 なかったので、98SEのCD-ROMで追加しました。

  • ranx
  • ベストアンサー率24% (357/1463)
回答No.3

UNIXならterra5さんの回答で概ね合っていると思うのですが、 Windowsということなので、恐らくcheさんのおっしゃる通りでしょう。

noname#2004
質問者

補足

C言語ではどうとかというよりも、OSによって違うんですね。

  • terra5
  • ベストアンサー率34% (574/1662)
回答No.2

mallocした領域が何か,解放しないとどうなるかは、 C言語というよりは、mallocの実現方法(実際のライブラリの中身)と、OSのメモリ管理方法によると思います。 通常は,mallocが使った領域はプロセスが終了した時点で消滅します(解放されます)。 問題があるとすれば、OSそのものが使うメモリの管理であるとか、 単一のプロセスだけで使わず複数のプロセスで使うようなものだろうと思います。 OSとはいってもプログラムの一種ですから、内部的にはmalloc(もしくは相当のこと)を行いますが, OSはシャットダウンまで終了しませんから、 プロセスを追加し、終了した時にメモリをきちんと解放していなければ、 それはOSというプログラムが終了するまで占有されたままになります。 また、ある種のメモリは複数のプロセスで使われるため、一つのプロセスが終了しても他のプロセスが使う、使っている可能性があるため、 簡単には解放できません。 本来なら使っているプロセスが全て終了した時点できれいになくなればいいのですが、 そうならない場合があり、 これも同様に無駄となります。 おそらく、詳しい話をするとなるとOSがどうやってメモリを管理しているかと言うOS内部の話になります。 例えば,あるOSはプロセスが起動すると、用途により何種類かに分類されたメモリを別々に割り当てます. 何故わけるかというと、メモリをより効率よく使うためや、実行を早くするため等です。 ・・・というような話になります。多分。

noname#2004
質問者

補足

>mallocした領域が何か,解放しないとどうなるかは、 >C言語というよりは、mallocの実現方法(実際のライブラリの中身)と、OSのメモリ管理方法によると思います。 処理系によって異なるので、一概に言えないということですね。 >通常は,mallocが使った領域はプロセスが終了した時点で消滅します(解放されます)。 正しいプログラムを書くときも、終了直前にfreeする必要はないという意味ですね。 >問題があるとすれば、OSそのものが使うメモリの管理であるとか、 >単一のプロセスだけで使わず複数のプロセスで使うようなものだろうと思います。 質問のソースではfreeしてもしなくても、コンピュータがおかしな動きをすることはないんですね。 >OSはシャットダウンまで終了しませんから、 >プロセスを追加し、終了した時にメモリをきちんと解放していなければ、 >それはOSというプログラムが終了するまで占有されたままになります。 「プロセスを追加する」とは、プロセスを起動させることですね。 プロセスを起動させるときに、そのプロセスが使うための領域をOSが確保するんだけど、プロセスが終了したら、OSがちゃんと解放しないとだめだということですね。 (OS自体はシャットダウンするまで終わらないから、OSが動いている以上、OSの確保した領域は、「終了したから自動的に解放される」とはならないんですね。 >また、ある種のメモリは複数のプロセスで使われるため、一つのプロセスが終了しても他のプロセスが使う、使っている可能性があるため、 >簡単には解放できません。 ひとつのプロセスが終了しても解放されないようにするにはどうすればよいのでしょうか。 いったいそのような領域はいつ解放されるのでしょうか。解放はfree関数で行うのでしょうか。(C言語の場合) >本来なら使っているプロセスが全て終了した時点できれいになくなればいいのですが、 >そうならない場合があり、 >これも同様に無駄となります。 なぜ「そうならない」のでしょうか。 あまり詳しい説明を求めるとたいへんなことになりますので、できればでいいです。

noname#2009
noname#2009
回答No.1

OSが確保する利用可能なメモリ、リソース領域は 限られているので、使用した後解放を行わないと、いずれ 蓄積され、OSがフリーズします。リソースメータ等で 蓄積状況は確認できます。Win98なら、 (特に)IE等の操作中にフリーズを起こすことが ありますが、ああいった具合になります。 ただ質問のソースでは少なくとも数十MBのリークを 起こさなければ、確認はしていくことはできないと 思われます。 昔、メモリ容量が現在よりずっと小さかったころは、 わずかのメモリ使用にも気を使っていたので、シビアに チェックされてましたが、現在は少々のものは平気です。 しかし、数時間~数百時間稼動するシステムでは、 1個所のリークコーディングが膨大な量のリークに つながるので許されません。 メモリリークとリソースリークについては、前者は アプリ終了時には解放、後者は再起動するもで解放 されない、です。要するに質問のソースでは無限ループ 等で常駐状態でなければ意味がないということ。 でも、C言語をやるのならば動的メモリの解放は、常識と して必須です。考えずに必ずやります。 ※自動変数はローカルメモリ、動的確保はヒープメモリ で自動変数にはあまり大きいサイズには利用でません。 そういった意味でも malloc を利用します。

noname#2004
質問者

補足

私はひとつひとつ丁寧に読むことにしますので、補足またはお礼までするのにお時間をいただきます。 >OSが確保する利用可能なメモリ、リソース領域は >限られているので、使用した後解放を行わないと、いずれ >蓄積され、OSがフリーズします。 まず確認したいのは、ここでおっしゃっていることを言い換えると、 「mallocしてfreeせずにプロセスが終了すると、その領域は他のプロセスで使えないので、OSであっても使うことはできない。 そのようなことを繰り返すと、使えない領域がメモリ上にどんどん増えてしまう。 OSがメモリを使おうとしても必要な領域が確保できないため、OSは活動できなくなり、人がコンピュータに働きかけても、反応しなくなってしまう。」 ということでよろしいでしょうか。 >リソースメータ等で >蓄積状況は確認できます。 リソースメータというのは、どこにありますか? アクセサリのシステムツールの中に「システム情報」というものがありますが、それでわかりますか? >ただ質問のソースでは少なくとも数十MBのリークを >起こさなければ、確認はしていくことはできないと >思われます。 質問のソースでも原理的には「解放しないためにコンピュータがおかしくなるプログラム」にはなっているわけですね。ただ、そのときに 100,000,000程度のサイズのmallocを繰り返して行わなければならないわけですね。 (「少なくても」というのですから、これでも十分ではないのかもしれないですね。) >しかし、数時間~数百時間稼動するシステムでは、 >1個所のリークコーディングが膨大な量のリークに >つながるので許されません。 この話はアプリが終了しないで継続して実行するときの話ですよね。 >メモリリークとリソースリークについては、前者は >アプリ終了時には解放、後者は再起動するもで解放 >されない、です。 メモリリークとリソースリークは違うものだとおっしゃっていますね。 質問のソースは、メモリリークであるので、終了時には解放されるんですね。 それでは質問のソースのプログラムを繰り返して何回行おうと、一回一回終了する限り、おかしな動きは起きないわけですね。 ただ、私はリソースリークというものを知らないのです。リソースリークというものはどのようにすれば起きるのでしょうか。 どのようなソースならばそれが起きるのでしょうか。 私には、ご回答の前半と後半とで、質問のソースに関して逆のことを言っているように感じられます。 「質問のソースで、多くのサイズをmallocさせれば、OSがフリーズする」とおっしゃっていますか? それとも、 「質問のソースでは、たとえどれだけ多くのサイズをmallocしても、OSのフリーズは起きない。」とおっしゃっていますか?

関連するQ&A

  • C言語のポインタ

    あまり意識せずにポインタを使っているせいか,次のプログラムではまってしまいました. #include<stdio.h> #include<stdlib.h> int main(void) {  int *p, q;  p = (int *)malloc(sizeof(int));  q = (int *)malloc(sizeof(int));  *p = 2;  printf("%d\n", *p);  return 0; } コンパイルエラーで実行ファイルが出力されません. このプログラムで変数qはなぜポインタじゃないのでしょうか? 次にtypedefでptr_intという型を定義したプログラムは, 上のようなエラーが出力されず,期待とおりの結果になりました. #include<stdio.h> #include<stdlib.h> typedef int* ptr_int; int main(void) {  ptr_int p, q;  p = (int *)malloc(sizeof(int));  q = (int *)malloc(sizeof(int));  *p = 2;  *q = 3;  printf("%d\n", *p);  printf("%d\n", *q); return 0; } typedefすることでなぜエラーを回避することができるのでしょうか? よろしくおねがいします.

  • C言語のプログラムでおかしな動作をするのですが教えて頂けないでしょうか?

    VisualStudio2008使用しています。 問題は、サイコロを200回振ってその出た目の数の個数分*を表示するプログラムです。 サイコロの目はランダムで出しています。 次のプログラムは正常に動作するものです。 /* #include <stdio.h> #include<stdlib.h> #include<time.h> #define N 200 int DICE(int min,int max); int main() { int n,i,j; int y[7]={0}; srand((unsigned int)time(NULL)); for(i=0;i<N;i++){ n=DICE(1,6); y[n]++; } for(i=1;i<7;i++){ printf(" %2d: ",i); for(j=0;j<y[i];j++){ printf("*"); } printf("\n"); } return 0; } int DICE(int min,int max) { return min+(int)(rand()*(max-min+1.0)/(1.0+RAND_MAX)); } */ 次のプログラムが問題で、授業で先生が配列にはstaticをおまじないとしてつけないと暴走すると言われたので、つけて見ると明らかに間違ってると思われるプログラムで動作するのですが原因を教えて頂けないでしょうか? 以下問題のプログラム! 配列の前にstaticをつけたら、添え字をいくつにしても正常に動作します。普通は添え自分しか領域って確保されないですよね??? /* #include <stdio.h> #include<stdlib.h> #include<time.h> #define N 200 int DICE(int min,int max); int main() { int n,i,j; //以下が問題の配列宣言 static int y[2]={0}; srand((unsigned int)time(NULL)); for(i=0;i<N;i++){ n=DICE(1,6); y[n]++; } for(i=1;i<7;i++){ printf(" %2d: ",i); for(j=0;j<y[i];j++){ printf("*"); } printf("\n"); } return 0; } int DICE(int min,int max) { return min+(int)(rand()*(max-min+1.0)/(1.0+RAND_MAX)); } 質問の意味が正確に伝わらなかった場合は補足しますので、ご回答よろしくお願いします。

  • C言語のint型の配列が分かりません

    #include<stdio.h> int main(void) { int str[ ]={0,1,2} printf("%s\n", str); return 0; } というプログラムをC言語でつくってみましたが動きません.(012と表示されて欲しかったのですが) int str[ ]={1,2,3}の部分をchar str[ ]={'0','1','2'}とすれば動きます. そこで質問なのですが, printf("~%s~", (配列名));  はchar型の配列にしか適応できないのですか? ※追記 puts関数の定義は int puts (const char *str); であるそうなので char型の仮引数にはchar型のアドレスを渡さなければいけません. ではprintf関数の定義は一体どんなものなのですか?

  • 動的なメモリ管理(複数の使用済みのメモリブロックの解放)

    氏名をmalloc()した配列に格納後,氏名アドレスと生年月日を組み合わせた構造体をさらにmallocし,そのアドレスをポインタ配列に登録していく。生年月日は,YYYYMMDD形式でキーボード入力されたデータを数値変換してlong型の構造体メンバーに格納する。 下記のプログラムでどこで使用済みのメモリブロックを解放すればよいか教えてください。お願いします。 #include <stdio.h> #include <string.h> #include <stdlib.h> #define DEBUG 0 /* debug mode 0:off 1:on */ #define BUFFERSIZE 11 #define MAX_PERSON 10 #define MAX_CHARS 10 #define BBUFFERSIZE 8 // YYYYMMDD typedef struct { char *name; //氏名 long birth; // 生年月日 YYYYMMDD }PERSON; int main(void){ char str[BUFFERSIZE]; /*氏名一時保存の配列,*/ char *st; //氏名保存配列 PERSON *person[MAX_PERSON]; /*構造体のアドレスを保存する配列*/ PERSON per[MAX_PERSON];//構造体保存配列 char bir[BBUFFERSIZE]; int count; int i; int j; int l; //文字列の長さ int top_index = 0; int bot_index; int day; int mon; int num ; int ch; char *tmp; printf("*** 入力された氏名をソートし、表示します ***\n"); printf("*** 最大入力件数10件(1文字目'0'で入力終了) ***\n"); putchar('\n'); for (i = 0; i < MAX_PERSON ; i++) { printf("氏名入力(10文字まで有効) > "); //氏名をmalloc()した配列に格納 fgets(str, BUFFERSIZE, stdin); l = strlen(str); if (str[l-1] == '\n'){ str[l-1] = '\0'; } else { while ( getchar() != '\n'){ } } if (str[0] == '0'){ break; } st = (char*)malloc(sizeof(char) * (strlen(str)+1)); strcpy(st,str);//\0も含まれてコピー printf("累計 : %d\n", i+1); //氏名アドレスと生年月日を組み合わせた構造体をmalloc() //そのアドレスをポインタ配列に登録 per[i].name = st; //生年月日入力 printf( "生年月日入力(YYYYMMDD) > " ); while(1){ l = 0; while ((ch = getchar()) != '\n' && ch != EOF) { if (l < 8) { bir[l] = ch; } l++; } num = 0; //数値に変換してlong型の構造体のメンバに保存 for ( j = 0; j < 8; j++){ num = num * 10 + (bir[j] - '0'); } printf("num : %d\n",num); per[i].birth = num; break; } person[i] = (PERSON*)malloc(sizeof(per[i])); person[i] = &per[i]; } count = i; printf("データ表示\n"); for (i = 0 ;i < count ; i++ ){ printf("%d : %s\n", i+1, person[i]->name); printf("%08d\n", person[i]->birth); } return 0; }

  • C言語のプログラムのメモリリークに関して

    動的メモリ管理を用いて,キーボードからの入力を行単位で辞書順にソートして出力するプログラムで、メモリリークが有るため解消したいのですが、freeをどのように用いれば良いのかが分かりません。 動的メモリについての理解が不十分であるため、自分なりにfreeを用いてみるとプログラムが途中で止まってしまい、解消することができません。 以下のプログラムは、自分なりにfreeを用いた部分を除けば、ソート後の出力は正しく出力されます。(メモリリークは発生します。) アドバイス、間違いの指摘等していただければと思います。お願いします。 環境は、Windows XP Professional SP3 32bitでVisual C++ 2008 Expressを使用しています。 #include <stdio.h> #include <string.h> #include <crtdbg.h> #include <stdlib.h> #define MAXLINES 20000 // 最大行数 #define LINELENGTH 20 // 1行の最大文字数 /* 標準入力からの入力を,一行づつ動的に確保したメモリに格納し, そのアドレスを文字列へのポインタ配列に保存する. Ctrl+Zで入力を終了する. lines : 文字列へのポインタの配列 numMax : 最大の読み込み行数*/ int ReadLines(char *lines[], int numMax){ int cnt = 0; static char buf[LINELENGTH]; while (cnt < numMax && gets(buf)) { lines[cnt] = malloc(strlen(buf) + 1); if (lines[cnt] == NULL) { printf("Allocation error.\n"); break; } strcpy(lines[cnt], buf); cnt++; } return cnt; } /* ポインタ配列の指す文字列を標準出力に表示 lines : 文字列へのポインタの配列 num : 行数*/ void PrintLines(char *lines[], int num){ int i; for (i = 0;i < num;i++) printf("%s\n", lines[i]); } /* ポインタの配列を,辞書順にソート lines : 文字列へのポインタの配列 num : 行数*/ void Sort(char *lines[], int num){ int i,j; char temp[LINELENGTH]; for(i=0;i<num;i++){ for(j=num-1;j>i;j--){ if(strcmp(lines[j],lines[j-1])<0){ strcpy(temp,lines[j]); strcpy(lines[j],lines[j-1]); strcpy(lines[j-1],temp); } } } } int main(){ int cnt,i; static char *lines[MAXLINES]; cnt = ReadLines(lines, MAXLINES); printf("----- %d lines -----\n", cnt); Sort(lines, cnt); PrintLines(lines, cnt); /*自分なりにfreeを用いた部分*/ for(i=0;i<cnt;i++){ free(lines[i]); } //メモリリーク情報の表示 _CrtDumpMemoryLeaks(); return 0; }

  • C言語について プログラムが動きません

    ゲームのプログラムを作りたいものです。 今、試作の途中の段階で以下のようなプログラムを作ってみたのですが、 コアダンプが表示されてうまく起動しません。 どの点を変更すればいいのか、教えてください。 使っている言語はC言語です。 よろしくお願いいたします。 #include <stdio.h> #include <string.h> struct monster{ int type; /* タイプ */ char trick[25]; /* 技 */ char trick2[25]; /* 技2 */ int tricktype; /* 技1のタイプ */ int tricktype2; /* 技2のタイプ */ int trickeffect; /* 技1の威力 */ int trickeffect2; /* 技2の威力 */ char name[10]; /* 名前 */ int attack; /* 攻撃力 */ int diffence; /* 防御力 */ int speed; /* 素早さ */ /* 1,fire 2,water 3,nature 4,thunder 5,wind */ }; char names[5][10] = {"v", "w", "x", "y", "z"}; main(){ int s = 0; int a[3]; int i; int m; struct monster monster[5] = { { 1, "a", "b", 1, 2, 120, 80, "v", 60, 60, 60}, { 2, "a", "b", 2, 3, 120, 80, "w", 60, 60, 60}, { 3, "a", "b", 3, 4, 120, 80, "x", 60, 60, 60}, { 4, "a", "b", 4, 5, 120, 80, "y", 60, 60, 60}, { 5, "a", "b", 5, 1, 120, 80, "z", 60, 60, 60}, }; printf("好きなモンスターを3つ選んでください\n\n"); while (s < 1){ for (i = 0; i++; i<3){ printf("%d体目を選んでください。\n\n", i+1); for(m = 0; m++; m < 4) printf("%d, %s\n", m+1, monster[m].name); printf("5, %s\n\n", monster[4].name); scanf("%d", a[i]); printf("%d体目 : %s\n\n", i+1, monster[a[i]-1].name); } printf("これでよろしいですか?\n"); for(i = 0; i++; i<2) printf("%d体目 : %s ", i+1, monster[a[i]-1].name); printf("3体目 : %s\n\n", monster[a[2]-1].name); printf("1、はい 2、いいえ\n"); scanf("%d", &i); if(i=1) return s = 1; else return s = 0; } }

  • C言語の穴埋め問題です

    次のプログラムは、初期化により文字列を定義し、辞書式配列にしたとき、どの文字列が先頭にくるかを調べるプログラムなのですが。■■■を教えてください #include <stdio.h> #include <string.h> #define N 5 //関数のプロトタイプ宣言 char *min(char *p[] , int n); int main(void) { char *p[N] = {"Hello" , "Hi" , "Happy" , "HaHaHa" , "Heaven"}; printf("辞書式配列で先頭となる文字列は%s\n" , ■■■); } char *min(char *p[] , int n) { int min; //最小値のアドレス Int i; //カウンタ min = 0; for(i = 1; i < n; i++){ if (strcmp(■■■ , ■■■) > 0){ ■■■= ■■■; } } return ■■■; }

  • C言語 動的なメモリの確保 実行できない

    malloc関数を使いメモリを確保しそこへ"ABCD"と記憶させ、ポインタ*Cを使い確保したメモリの内容を表示するプログラムです。 ********************************************* #include <stdio.h> #include <stdlib.h> int main(void) {   int i;   char *C;   C = (char *) malloc (sizeof(char) * 5);   C = "ABCD";   for(i = 0; i < 5; i++){     if(C[i] != NULL){       printf("%s", C[i]);    ←※エラー※     }   }   free(C);   return 0; } ********************************************* 正常にコンパイルできますが実行エラーになります。VCを使いF10のデバッグテストで※のところエラーになります。なぜなのでしょうか?

  • c言語についての質問です。

    #include<stdio.h> int main(void){ int a; printf("1文字たいぷしてください。\n"); scanf("%d",&a); if(a>=65 && a<=90){ printf("大文字です。\n"); } else if(a>=97 && a<=122){ printf("小文字です。\n"); } else{ printf("大文字でも小文字でもありません\n"); } return 0; } このプログラムは正しくなくて、 intをchar %dを%cにかえなければなりません。 なぜintはダメなんでしょうか? できれば丁寧に教えてください。 お願いします。

  • C言語<素数を求めるプログラム>

    #include<stdio.h> int j; int prime(int n) { int i; if(n < 2) return 0; if(n == 2) return 1; if(n%2 == 0) return 0; for(i = 3; i*i<= n; i += 2){ if(n%i == 0) return 0; } return 1; } int main(void) { int n; for(n=1; n <= 1000; n++) { if(prime(n)){ printf("%d\n",n); j++; } } printf("素数の個数は全部で %d 件見つかりました。\n",j); return 0; } このプログラムは1から1000までの素数のみを表示させるプログラムでありますが、このアルゴリズムが全くわかりません。 int prime(int n)の中身のアルゴリズムがどういう仕組みになっているのかお分かりになりますでしょうか?