• ベストアンサー

動的メモリ利用の目的

情報分野を学習中の大学生です。 C言語の動的メモリ利用について質問させて頂きます。 先日、基数ソートを実装している際に、動的メモリを利用しました。 ソートデータ数の都合上(最大10桁100万個)、確保すべきバッファ領域が膨大だったためです。 ※実際に必要だったバッファ:buf[0][0] - buf[9][1000000-1] ここで私が動的メモリを利用した動機は「バッファ領域でかすぎるからメモリ圧迫するし動的メモリのほうがいいかな?」といったものです。 コードを書いているうちに、この認識の正誤と、どういったケースで動的メモリを扱うべきか気になりました。 御回答宜しくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.3

> 「バッファ領域でかすぎるからメモリ圧迫するし動的メモリのほうがいいかな?」 その理由で動的なメモリーの割り当てを利用するというのは、誤りです。 普通、それのことはバッファ領域ではなく、スタックというように思います。バッファという言葉には何かのデータの一時置き場という意味しかないので、スタック上に取るのもヒープ上に取るのも自由です。少量のものはスタックにとり、大量のものはヒープにとるのが普通でしょう。 ただ、ヒープに取るものは必ずしも動的にメモリーを割り当てる必要はありません。例えば、グローバル変数に取れば自動的にヒープに容量が割り当てられます。 たしかに、一般にスタックの伸びしろのほうがヒープよりも少なめになっていますが、必ずしもそれが正しいとはいえません。例えば、Unix系のOSだとlimitなどで簡単にスタックやヒープのサイズを変更できます。もちろん、動的に割り当てられるメモリーもヒープ上に取られますので、そういう使い方も可能ではありますが。 > どういう時に動的なメモリー割り当てを利用するか? 配列と変数と式だけのToyプログラムを書いているうちは特に動的なメモリーの割り当ては必要ないと思います。 実用的なプログラムは普通のユーザーから様々な入力をとり、それを複数の関数で処理します。スタック上に取られている変数だと、その関数を抜けたら開放されてしまうので、複数の関数で処理を行うのが大変困難です。そして、どれだけの容量を確保したらいいかもユーザーが具体的に指示するまでわかりません。例えば、ソートをする場合でも10個のデータをソートするのか10万個のデータをソートするのかで必要なメモリーは大いに違います。ヒープに予め確保しておくと、無駄ですし、想定よりも大きなデータが来た時に処理できません。(ちなみに、普通のOSはデマンドページングをするので、10万個分のメモリーをヒープにとって、10個しか来なくても、実際にメモリーを使う量は微々たるものですが) また、モジュール化/カプセル化とデータ抽象化を学ぶと動的なメモリーの割り当ての必要性に気づくでしょう。この場合、あなたが書いたライブラリーが呼ばれた時に一度にすべての処理をするのは不可能なので、ライブラリーの利用者の指示に従ってすこしずつ処理を進めますが、その中間状態を保存しておくのにスタックは不向きです。また、その場合、どれだけメモリーを用意したらいいのかわからないので、ライブラリーの利用者が特定の関数を呼び出した時に動的なメモリーの確保を行います。 例えば、ファイルの入出力に使われるfopenは内部で動的なメモリーの確保を行っています。利用者は同時に読み書きするファイルの個数分fopenを呼び出します。そして、ファイルの読み書きをするfscanfやfprintfの実行に必要な様々なデータはその動的に確保されたメモリーに入っています。 複数の人で開発している場合も同じ事です。他の人が自分が書いた部分でどの程度メモリーを必要とするか不明なので、必要な分だけ動的に割り当てるようにします。 mallocなどで動的にメモリーが割り当てられる場合、その領域は重複しないので、確保したコードの専用領域として使えます。一つのプログラムが同時に複数の処理を行うマルチスレッドプログラムでは、一つ一つのスレッド (処理を行う一つ一つの単位) が別々の処理を行います。この時、スレッドに動的に割り当てられたメモリーは御行儀よく使えばそのスレッドからしか読み書きされないので、他のスレッドのことを考えずにプログラムを書けるようになります。 これが、逆に動的に割り当てられたメモリーではなく、グローバル変数になっていると、他のスレッドが変更を加える可能性があるので処理が終わるまでロックを取るなどをする必要があり、面倒くさく、性能にも悪い影響を与えます。 と、説明してきましたが、まとめると次の3つですね。 - 複数の関数が同一のデータを取り扱い、プログラムの動作によって必要となるメモリーの量や種類が多いに変わるとき - データの抽象化をしたいとき - マルチスレッドのプログラムを書いていて、グローバル変数を使いたくないとき

その他の回答 (2)

  • hashioogi
  • ベストアンサー率25% (102/404)
回答No.2

JPEG画像をビットマップに変換するような処理を考えます。デジカメの種類によって画像サイズが異なりますから予め固定的な領域を確保しておくわけにはいきません。最大でこのサイズまでしか扱わないという制限を設けておけば別ですが。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

100万個ともなれば動的にメモリを確保すべきだとは思うけど, 連結リストを使えばそんなにメモリをたくさん必要ともしない.

関連するQ&A

  • 配列のメモリの確保

    先日メモリについてご質問させていただいたものですが、 今ファイルから読み込んだ文字列を配列に格納する作業を行なっています。 今は char buf[1000]; FILE fp; if((fp=fopen("○○.txt","r")) ==NULL){ printf("ファイルが開けません"); } while(fgets(buf,1000,fp) != NULL){ としてファイルを一行ずつ読み込んでその後単語ごとに配列に組み込みます このときファイルの文字列を格納する配列はbuf[1000]ですが このメモリでは足りないかもしれませんし多すぎるかもしれません。 足りない場合はエラーになるし多すぎる場合はメモリの無駄ですよね。 このような場合はメモリを取り直すべきなのでしょうか?その場合 どのような方法がありますか?調べてもint型の領域確保とかそういうのはあるんですがファイルから読み込んだ文字列の領域確保とかは見つからなかったので教えて下さい。

  • GMA950のメモリが56Mしか確保されません

    945GMチップセットのGMA950で動作しているノートPCのグラフィックメモリ領域を調べた所、56MBしか確保されていませんでした。 ちなみに本体のメモリは増設して2Gバイトになっています。 GMA950は確か実装メモリの使用状況によって最大128Mのグラフィックメモリを確保すると聞いていたのですが、これはどうしてでしょうか? また、強制的にVRAMに128Mバイトを割り振ることは可能でしょうか?

  • メモリ不足になってしまう。

    教えてください。 現在陥っている現象:「メモリ不足になってしまう」配列の領域をRedimで動的に確保しようとしています。 例えば、 dim A() as byte dim B() as byte dim C() as byte redim A(8000,60000) redim B(8000,60000) redim C(8000,60000) 上記のように配列を確保する予定なのですが、 メモリ不足になってしまいます。 ひとつの変数の容量が480MB程度であると思います。 3つ全部でも1440MBであるのですが、物理的な メモリ容量は、512M*4を実装しています。 上記の変数名で言いますと、 Aの変数の領域確保には問題なく成功するのですが、 その次の行のBのところでエラーになります。 現在、物理的なメモリには空きがあるにもかかわらず このような現象になってしまい、困っています。 どなたか原因解決の糸口になるような回答をお持ちの方、 教えてください。

  • パソコンのメモリについて

    windows 7 32bitを利用していますが、プリンタを利用する際に動きが遅くなるため、メモリを増設すると解決するのかなとふと思いましたが、、、 現在:実装メモリ 4GB です。 パソコンの仕様とみると最大メモリ 16GB(SO-DIMMスロット×2)となっていますが、注意書きの欄に[32bit版のwindows7では、メモリ4GB以上搭載時でもすべての領域を使用することはできません。OSが使用可能な領域は3GBとなります。なお、装置構成によって利用可能なメモリ容量は異なります。 と書かれています。 メモリ4GB以上搭載時でもすべての領域を使用することはできません。 というのがどういう意味なのかが分からないので、教えて頂けますでしょうか。 メモリを増やしても意味が意味が無い、ということなのでしょうか。。。

  • Redhat Linux7.3のメモリ使用率が95%になってしまいました

    現在、サーバをデータセンターへ置いているのですが、サーバのメモリ使用率が90%を超えているというアラートがあがってきました。 実際にメモリの使用内容をみてみると、キャッシュとバッファが領域をとっているだけのように見えます。 Linuxはメモリの確保が特殊なのでしょうか? データセンターにはメモリ使用率の監視をとめてもらった方がいいのか悩んでます。 どこかに正式な文章とかありましたらリンク先をご紹介していただけないでしょうか。

  • LinuxのDMA転送でのメモリ操作について

    Linux初心者です。 ユーザモードで動作しているプロセスからデバイスドライバに対してDMA転送要求を行った場合、ドライバでDMAバッファ用のメモリを確保すると思います。 ドライバはDMA転送用バッファとして、GFP_DMA指定でkmallocし、確保されるメモリ領域はZONE_DMAだと思います。 (PCIデバイスドライバの場合は、上記指定は必須ではないみたいですが。) ここで疑問なのですが、カーネルモードでしかアクセスできないZONE_DMA領域を、ユーザモードのプロセスがどのように扱うのでしょうか? ある本で「ユーザモードで動作中でもシステムコールに関してはCPU内でカーネルモードで動作する」というのを見たことがあるのですが、これによってZONE_DMA領域にアクセスできるようになるということでしょうか? ご存知の方がいたら、よろしくお願いします。 また、そもそも質問内容(前提)の間違えなどありましたらご指摘いただきたいです。

  • new、memset()、エラー

    new は何型を返すんですか? new の定義が詳しく書いてあるサイトを紹介してください。 new して確保した領域のメモリは全て0で初期化されますか? それが分からなかったからmemset()で0にしてみたら、 memset()の部分で実行エラーでした。 new の領域をmemset()してはいけないんですか? #include <iostream.h> main(){ char *buf = new char[100]; memset(buf, 0, 100); delete []buf; }

  • ポインタで、実装メモリの先頭から100バイト分参照してみたい

    いつもお世話になります。 Cの質問です。 ポインタの勉強中なのですが、ポインタを用いて、実装メモリの先頭から100バイト分を参照してみたい、と思いました。 先輩が言うには「メモリの先頭領域にはメモリのメーカーとか、文字コードが順番に入ってるよ」とのことなのですが、どうにもプログラムが作れません。 mallocでは、どうやら「コンパイル時にメモリ領域を確保する」らしく、指定したメモリ位置(つまりアドレス0)からxxバイト分確保することはできないようです。 私が試しに書いてみたソースは以下になります。 #include<stdio.h> #include<stdlib.h> int main(void){ int i; char *p; p = (char*)malloc(sizeof(char) * 100); for (i=0;i<100;i++){ printf("%c",*p); p++; } return (0); } アドバイスでもかまいませんので、ご指導いただけたらと思います。 よろしくお願いいたします。

  • 物理メモリとページファイル及びスワップについて

    参考サイト:http://www.atmarkit.co.jp/fwin2k/win2ktips/076pgfilesize/076pgfilesize.html メモリについて調べていて疑問に思ったことがあるので質問させてもらいます。 ・今まで仮想メモリというのは物理メモリの不足を補うために適時HDDに確保された領域(ページファイル)のみを示す用語だと認識していたのですが、そうではなく「仮想メモリ=物理メモリ+ページファイル」という実質使用可能なメモリの総量という意味の言葉ですか? ・例えば1GBや2GBなど、十分な物理メモリがあるとき、トータルで使用されるメモリがそれよりも少ないならば、HDDに領域を確保しない。つまり物理メモリを超えそうになったときに初めてページファイルは作成され、物理メモリで足るようになれば解放されるものだと思っていました。しかし、参考サイトを読んだ限りでは「ページファイルは必要に応じて生成されるのではなく、恒常的に存在し、使用頻度の低いデータはメモリにいくら空きがあったとしてもスワップされる。」と認識しました。必要に応じてページファイルが適時拡張されるのはいいのですが、ページファイルはどんなに物理メモリが使用状況に対して十分でも常に存在するものなのですか?また、物理メモリが十分に足りていても使われないデータはスワップアウトされてしまいますか? ・ページファイルはデフォルトで物理メモリの1.5倍の大きさがあるらしいのですが、当然このファイルがHDD上にとった領域は別のファイル(.txtなど)の保存領域としては利用できませんよね? 長くなりましたが、以上4点についてご教授お願いします。説明不足がありましたら追記しますのでよろしくお願いします。

  • C言語のメモリ領域確保

    ポインタ変数ををmain関数で宣言し、関数test()にて必要分だけ領域確保してそのアドレスをmain関数のポインタ変数に渡して利用することは可能でしょうか。 (サイズのわからないテキストデータを、十分に大きな配列に入れるのではなく、関数でメモリを動的確保して無駄の無い配列に入れたい等) C言語ではやはり無理で、構造体のリストにするのが一番でしょうか。 初歩的なことで申し訳ありませんがどなたかお願いいたします。