mallocの挙動について

このQ&Aのポイント
  • C言語で書かれた32bitアプリを32bitのサーバAと64bitのサーバBで実行したところ、サーバBではmallocでNULLポインタが返され異常終了した。
  • サーバAは正常終了し、期待した実行結果が得られています。
  • プロジェクトの設定で2GBを越えるアドレスをサポートするオプションを設定すれば、サーバBでもアプリが正常終了するようになりました。しかし、このオプションがない場合にメモリが多いサーバでmallocのメモリ確保が失敗する関連性については理解できていません。
回答を見る
  • ベストアンサー

mallocの挙動について

現象自体は解決してるのですが、私自身イマイチ理解できていないので質問させて下さい。 [問題] C言語で書かれたある32bitアプリを32bitのサーバA、64bitのサーバBでそれぞれ実行すると、サーバAは正常終了し、サーバBはmallocでNULLポインタが返され異常終了した。  サーバA:Windows Server 2003 R2 Standard Edition SP2 メモリ4GB実装  サーバB:Windows Server 2003 R2 Standard x64 Edition SP2 メモリ6GB実装 ・ソースをデバッガで確認したがメモリリーク等はなさそう。(_CrtSetDbgFlagや_heapchk()も試しました)。 ・実行結果もサーバAは期待した実行結果が得られています。 ・メモリの最大使用量は1.6GB弱の様です。 ・開発環境は”WindowsXP+Visual Studio 2003”です。 ・両サーバ共に私の占有状態で、余計なプロセスは実行されておりません。 ・サーバAは3GBオプション(boot.ini)を使用していません。 [解決法] プロジェクト-プロパティ-リンカ-システム-大きいサイズのシステムの項目で、  ”2GBを越えるアドレスをサポートする(/LARGEADDRESSAWARE)” に設定してビルドするとサーバBでもアプリが正常終了するようになりました。 [質問] 私の認識としては上記オプションは2GB以上のメモリを使用できるようにするだけで、使用するメモリ量が2GB以内なら、どちらのサーバで実行しても同じだと思っていたのです。 なので、このオプション無しでメモリが多い方のサーバBでmallocのメモリ確保が失敗する現象の関連性がいまいち理解できていません・・・ この件で知識をお持ちの方ご教授願えませんか?

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

  • ベストアンサー
  • chie65535
  • ベストアンサー率43% (8525/19377)
回答No.1

・2Gを超えるメモリをサポートしない場合の挙動 「メモリアドレスは2Gを超えない」と言う前提で処理されます(メモリアドレスを32ビットで扱います) 従って、OSに対してメモリ確保を要求した時、戻り値を「32ビット整数で、正数なら成功、負数なら失敗」と扱います。 なので、OSが「2G以降のアドレスを返す」と「32ビット整数で負数」となるため、メモリ確保に成功しているにも関わらず、失敗したと誤解して処理を継続します(最終的にはmallocがNULLを返します) サーバーAでは、3GBオプションがオフなので「ユーザーメモリは前半2G、カーネルメモリは後半2G」となります。 ユーザーメモリが前半2Gの範囲に限定されるので、OSは、メモリ確保成功時「2G以降のアドレスは返さない」ので「32ビット整数で、正数なら成功、負数なら失敗」と扱っても問題は起きません。 しかし、サーバーBでは(デフォルト設定ならば)「ユーザーメモリは前半4G、カーネルメモリは後半2G」となります。 ユーザーメモリが前半2Gの範囲に固定されないので、OSは、メモリ確保成功時「32ビット整数で、正数や負数になるアドレスを返す」ので「正数なら成功、負数なら失敗」と扱うと問題が起きます。 ・2Gを超えるメモリをサポートする場合の挙動 「メモリアドレスは2Gを超える」と言う前提で処理されます(メモリアドレスを64ビットで扱います) 従って、OSに対してメモリ確保を要求した時、戻り値は「64ビット整数で、正数なら成功、負数なら失敗」と扱います。 成功時には「32ビット整数で負数になる、2G以降のアドレスも、正しくアドレスとして扱う」ので、成功しているのに失敗と勘違いする事はありません。 例え「メモリ使用量が2G未満」だとしても「物理アドレスが2G(0x7FFFFFFF)を超える可能性があるシステム」では「2Gを超えるメモリをサポートする」にしなければなりません。 今回の場合、サーバーAは「ユーザーメモリの物理アドレスが0x00000000~0x7FFFFFFFの範囲に限定される」ので「2Gを超えるメモリをサポートしない」でも「偶然、うまくいっただけ」です。 もし、サーバーAに「3Gオプション」を付けていたら「ユーザーメモリの物理アドレスが2G(0x7FFFFFFFF)を超え、サーバーBと同様の結果になっていた筈です。 重要なのは「使用量が2Gを超えるか?」ではなく「メモリアドレス(物理アドレス)が2Gを超えるか?」なのです。

Nu-GGG
質問者

お礼

なるほど! 目から鱗です! 最近、メモリ使用量がネックになるシステムをいっぱい改修してたので、どうもメモリ使用量に固執してたみたいです。 冷静に考えるとアプリが32bitである以上、OSから2GB以降のアドレス返されたらどうしようもないですよね^^; 大変納得できました。丁寧に解説頂き有難うございました。

関連するQ&A

  • mallocについて

    mallocについて 現在C言語でプログラムをかいているのですが、原因不明のエラーが出て困っています。 それはmallocによる動的メモリ確保を行ったとき、 (float *)malloc(sizeof(float)*200)の場合大丈夫ですが、 (float *)malloc(sizeof(float)*320)ではエラーが出てしまうのです。 しかし (float **)malloc(sizeof(float*)*640)とした場合エラーは出ませんでした。 これは何が原因でエラーが出ているのでしょうか? ちなみにコンパイルはできており、実行したとき プログラム名(7637) malloc: *** error for object 0x100ff7a08: incorrect checksum for freed object - object was probably modified after being freed. *** set a breakpoint in malloc_error_break to debug というエラーがでます。

  • malloc.cを見たい

    TurboLinux10でとあるプログラムを実行していましたが、 coreファイルを吐き出してGUIが終了してしまうことがあります。  gdb -c core.**** 実行ファイル名 というコマンドでGUIが終了した原因を調べたところ、  kernel/malloc.c:3415  kernel/malloc.c そのようなファイルやディレクトリは見つかりません。 と出ていました。 malloc.cというソースファイルを見たいのですが、 どこから入手すればよいでしょうか。 TurboLinux10は「全パッケージ」を選択してインストールしており、 カーネル再構築もできるのでカーネルのソースファイルは入っているはずですが、 最低3415行もあるmalloc.cは存在しません(十数行の同名ファイルはありました)。 TurboLinux10DesktopのソースファイルをFTPサーバーからダウンロードしようと、 ftp://ftp.turbolinux.co.jp/pub/TurboLinux/TurboLinux/ia32/Desktop/10/source/SRPMS/ に行ってみたのですが、 勿論malloc.cが入っていそうなパッケージがわかりません。 (そもそも、「malloc.cが見つからない」と出た場合にmalloc.cを入手してくるべきなのでしょうか)

  • インデックスの断片化が解消されません

    SQL Server 2005 Standard Edition を使っています。 インデックスが断片化しているので、再構築を実行するのですが、実行直後に断片化率を見ても、0%にならない場合があります。これは何故なのでしょうか。サーバのメモリは1GBですが、メモリが少なすぎるのでしょうか。

  • ヘッダファイル? malloc.hとかは自分で足したり作ったりできるのでしょうか

    CmachineでC言語を勉強していて、メモリの確保までたどり着きました。 でも、プログラムを実行できないんです。調べたところ、malloc.hやmemory.hがCmachineのincludeフォルダに入っていませんでした。 char *b; b = (char *)malloc(sizeof(char)*200); とか書いても実行できませんよね・・・。Cmachineは勉強するのに便利だし、ヘッダファイルを追加できないのでしょうか。includeフォルダにテキストファイルで書いて入れればできそうなのですが。 ちなみに、Visual C++ Express Editionでも同じプログラムを実行したのですが、できませんでした。あれもヘッダファイルが無いとかの問題なのでしょうか。あれは操作が複雑で難しくてよくわかりません。 アドバイスやいい方法をご存知の方、教えてください!!

  • 取ってこれないメモリのはずのmallocの動作

    こんにちは.mallocの動作,及びコンパイルの仕様について質問です. 以下のような.cのプログラムを書いてgccでコンパイルして実行してみました. #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main(int argc, char **argv) { int size = 0; int *tmp = NULL; while(1){ printf("Size %d\n", size++); tmp = (int *)malloc(size * 1024 * 1024); usleep(10000); free(tmp); } } このプログラムだと,heapから取ってこれないぐらい大きいメモリだとなんか起きるのかな?どれぐらいまで取ってこれるのかな?という興味でやってみたのですが, 1)32bit, 64bit ubuntu のgcc (バージョンは覚えてないですけど一番updateされてると思います)では永遠に回り続け, 2)Mac のgccだとSize=2048以降,つまり2GB以降で a.out(1145,0x7fff73a1b310) malloc: ***mach_vm_map(size=18446744071562067968) failed (error code=3) *** error: can't allocate region というエラーをはきます.(プログラムは回り続けます) a. この違いはgccの違いからくるという理解でよろしいですか?Macでの2GBというのもコンパイル側の制約なのでしょうか? b. ubuntuでは実際何が起こってるのでしょう?1000GBとか絶対取れないですけど回ってますし. c. ubuntuで実際に何が起こってるかを確認する方法はありますか.アセンブラとか吐かせるのでしょうか? お時間のあるときに回答してもらえたらと思います.

  • SQL Server 2008 Standardをインストール時にエラーになる

    Windows Server 2008 Standard 32bit Edition に SQL Server 2008 Standardをインストールしています。 しかし、"セットアップを実行するには、4.5以上のWindowsインストーラが必要です。"というメッセージが出てきました。 それで、Windows Installer 4.5 Redistributable をインストールしようとしていますが、 ダウンロードするファイルがいくつもあり、どれが正しいのか解りません。 Windows Server 2003に対するファイルはあるのですが、2008に対するファイルがありません。 どのファイルをダウンロードしてインストールしたら良いのでしょうか? 宜しくお願いします。 OS: Windows Server 2008 Standard 32bit Edition CPU: Intel Core 2 Duo E7300 @2.66GHz Memory:4.00GB HD空き領域: C 160GB です。

  • malloc関数によるメモリの確保

    C初心者です。 malloc関数によるメモリの確保に関して教えてください。 2次元配列のサイズに対してmalloc関数の引数値をたとえば、 (double*)malloc(datasize*sizeof(double)) などとしメモリ領域を確保すると、メモリアドレスはデータのサイズ によらず一定 1234044、1234048となります。 データサイズを大きくし、datasize*sizeof(double)が16Kバイトを超えるとcmd.exeがエラーとなり落ちます。 デバックモードで実行すると 「"System.AccessViolationException"のハンドルされていない例外が不明なモジュールです。で発生しました。 追加情報:保護されているメモリに読み取りまたは書き込み操作を行おうとしました。他のメモリがこわれていることが考えられます」 というメッセージがでます。 コンパイラはExpressEdition2008です。 この現象を回避するにはどうすべきか、なぜこのようなことが起こるのかご教授ください。 よろしくお願いいたします。

  • mallocの使い方

    すいません初心者な僕に教えて頂きたいことがあるます。 1行64バイトのファイル(行数可変)のデータに何回も文字列の検索を行ういアウトプットするプログラムを作っています。 fgetsを使い何回もファイルを読み込んで一行ずつ比較するというようにできたにはできたのですが、 行数可変で多い場合100000行超えたりするファイルに対してはえらい時間がかかります。 mallocが良いとはわかったのですが、なかなかうまく組めません。 ご教示願えませんでしょうか。 ↓のような文字列があり 型番 要素1 要素2 要素3 A 1044 100 123 A 1055 277 155 B 100 115 224 C 115 277 885 B型番の要素2がB型番の要素と一致した時B型番の要素2と要素3に一致するC型番の文字列を探しだすというようなプログラムです。 これがA、B、C共にソートされずランダムに並んでいます。 検索する度に毎回ファイルを読み込まず、一括でメモリに溜め込み、その中から文字列を抜き出し比較したいと思っています。。 長くなりましたが宜しくお願いします。

  • fastcopyとタスクスケジューラ使用時の挙動

    こんにちは。 社内でサーバAの特定データをサーバBに上書きコピーしたいのですが、下記の現象に困っています。 ◎環境:windows2008server update済み ◎fastcopy2.08 ◎対象batファイル(サーバA内) echo 処理開始 C:\@Fujixerox\Backup\FastCopy208\fastcopy.exe /cmd=force_copy /auto_close /open_window /error_stop=TRUE /log /from_date="- 4D" "D:\data_ele" "/to=\\サーバB\data_ele" @echo off call "Z:\file-backup2.bat" echo 処理終了 このバッチファイルは単独では正常に起動しますし、タスクスケジュールでも全般タブ 内のセキュリティオプションで「ユーザーがログインしている時のみ実行する」を選ぶと、タスク実行完了します。 ところがセキュリティオプションの「ユーザーがログインしているかどうかにかかわらず実行する」を選ぶと タスクは実行するのですがBATファイルのfastcopyコマンドラインのところで止まって、タスクが完了しません。 (ログ開始の部分はログに記載されていました) そこで試しに以下のことを実験しました。 1.新たにBATを作り、転送先を別サーバではなくサーバA内の別ドライブに設定し実行すると、fatcopyも正常に動きました。 2.そのBATファイルで、転送先をサーバBにすると、上記と同様の現象で、タクスが完了しませんでした。 常にログイン状態はマズイので、なにか対策がわかる方がおいでれば教えてください。 fastcopyというよりもタスクの問題のような気がしますが、よろしくお願いします。 管理者権限からみかなと思いますが。

  • 64bitサーバーへ32bitXPの接続について

    この度、ファイルサーバーを購入することになり、 DELLのオンライン見積もりを行なっているのですが、64bitのOSしか選択できません。 そこで質問なのですが、64bitOSのファイルサーバーであってもXP(32bit)は問題なく アクセスやファイル保存は行えるのでしょうか? サーバー以外は全て32bitのXPです。 サーバー構成予定: OS:Windows Server 2012 Standard Edition x64 メモリ:2GB HDD:3TB(RAID5)