none
32ビットOSで2G近くのメモリを確保したい RRS feed

  • 質問

  • C#でオンメモリで動作するデータベースを作っています。
    開発PCは3GBのメモリを搭載しています。
    ユーザが使えるのは2Gまでと聞いています。勿論メモリ管理のオーバヘッドやプログラムをロードしているため全部を使えないことは理解しています。
    byte[]bytes=new byte[1024*1024*1024];
    と1GBのメモリを確保しようとするとOutOfMemoryExceptionが発生します。
    マシンによっては800MBぐらいでもおきるようです。
    内部ではfixedでunsafeコードで書いているため、実際にはMarshal.AllocHGlobal(int cb)でも良いのですが例外がおきるバイト数は変わりません。
    もう少し大きく確保する方法はないでしょうか?
    これは64ビットOSになっても同じような現象が起きるのでしょうか?
    2008年4月20日 11:28

回答

  •  和和和 さんからの引用

    内部ではfixedでunsafeコードで書いているため、実際にはMarshal.AllocHGlobal(int cb)でも良いのですが例外がおきるバイト数は変わりません。
    もう少し大きく確保する方法はないでしょうか?

    ありません。

     

    仮想メモリ空間はハードディスクと同じで、断片化が起きます。

    空き容量自体はある程度あっても、連続した領域がないんじゃないかと思われます。

     

    解決策としては同時にメモリを必要としないように組み直すか、連続した領域とせず、細かい領域を確保するようにするしかないでしょう。

    #もちろん、細かく確保しても空き容量には限界があります。

     

     和和和 さんからの引用

    これは64ビットOSになっても同じような現象が起きるのでしょうか?

    64ビットアプリケーションとして組めば、連続した領域として確保できるかもしれませんが、64ビットOSでも32ビットアプリケーションとして実行される場合は無理でしょう。

    #64ビットについては経験がないため、不確かです。
    2008年4月20日 13:56
    モデレータ
  •  Azulean さんからの引用

    仮想メモリ空間はハードディスクと同じで、断片化が起きます。

    空き容量自体はある程度あっても、連続した領域がないんじゃないかと思われます。

     

    仮想メモリ空間ではなく、

    ヒープの断片化です。

     

     和和和 さんからの引用

    開発PCは3GBのメモリを搭載しています

    当然、物理メモリは全く関係ありません。

     

    64bitで実行すればヒープも64bitの仮想メモリから確保しますので、

    1~2G程度のヒープは普通は問題なく確保できます。

    当面は7000~8000GB程度まで使えるはずです。

     

     和和和 さんからの引用

    もう少し大きく確保する方法はないでしょうか?

     

    少しというのがどのくらいなのかわかりませんが。

    数バイト~数kByteとかいうオーダーなら

    参照してるDLLを減らすとか、そういった手でいけるとおもいます。

     

    また、.Netでできるかわかりませんが、

    HeapSetInformationを用いてLow-fragmentation Heapを有効にすると

    多少断片化が抑えられるのでよくなる場合もあります。

    (でも、危険かもしれない…)

     

    OSによってはBoot.iniに「/3GB」や「/USERVA」を追加することで

    2GByte以上のユーザー空間を扱えるようにすることもできます。

    ユーザー空間を最大で3Gまで拡張できますので、

    1GByteを.Netや他のランタイム、DLLにとられたとしても2GByteまで扱えます。

    OS設定に手を加えるのがアリなら、この選択が楽です。

     

    でも。

    ヒープは本質的にフラグメントに弱い仕組みですので、

    そんな大きなヒープを確保するのをやめるのが一番です。

     

    どんなオンメモリDBなのかわかりませんが、

    状態が変わるたびに確保・解放するとか、

    テーブルごと、レコードごと、エントリごとに確保・解放するほうがいいでしょう。

     

    2008年4月20日 18:48

すべての返信

  •  和和和 さんからの引用

    内部ではfixedでunsafeコードで書いているため、実際にはMarshal.AllocHGlobal(int cb)でも良いのですが例外がおきるバイト数は変わりません。
    もう少し大きく確保する方法はないでしょうか?

    ありません。

     

    仮想メモリ空間はハードディスクと同じで、断片化が起きます。

    空き容量自体はある程度あっても、連続した領域がないんじゃないかと思われます。

     

    解決策としては同時にメモリを必要としないように組み直すか、連続した領域とせず、細かい領域を確保するようにするしかないでしょう。

    #もちろん、細かく確保しても空き容量には限界があります。

     

     和和和 さんからの引用

    これは64ビットOSになっても同じような現象が起きるのでしょうか?

    64ビットアプリケーションとして組めば、連続した領域として確保できるかもしれませんが、64ビットOSでも32ビットアプリケーションとして実行される場合は無理でしょう。

    #64ビットについては経験がないため、不確かです。
    2008年4月20日 13:56
    モデレータ
  •  Azulean さんからの引用

    仮想メモリ空間はハードディスクと同じで、断片化が起きます。

    空き容量自体はある程度あっても、連続した領域がないんじゃないかと思われます。

     

    仮想メモリ空間ではなく、

    ヒープの断片化です。

     

     和和和 さんからの引用

    開発PCは3GBのメモリを搭載しています

    当然、物理メモリは全く関係ありません。

     

    64bitで実行すればヒープも64bitの仮想メモリから確保しますので、

    1~2G程度のヒープは普通は問題なく確保できます。

    当面は7000~8000GB程度まで使えるはずです。

     

     和和和 さんからの引用

    もう少し大きく確保する方法はないでしょうか?

     

    少しというのがどのくらいなのかわかりませんが。

    数バイト~数kByteとかいうオーダーなら

    参照してるDLLを減らすとか、そういった手でいけるとおもいます。

     

    また、.Netでできるかわかりませんが、

    HeapSetInformationを用いてLow-fragmentation Heapを有効にすると

    多少断片化が抑えられるのでよくなる場合もあります。

    (でも、危険かもしれない…)

     

    OSによってはBoot.iniに「/3GB」や「/USERVA」を追加することで

    2GByte以上のユーザー空間を扱えるようにすることもできます。

    ユーザー空間を最大で3Gまで拡張できますので、

    1GByteを.Netや他のランタイム、DLLにとられたとしても2GByteまで扱えます。

    OS設定に手を加えるのがアリなら、この選択が楽です。

     

    でも。

    ヒープは本質的にフラグメントに弱い仕組みですので、

    そんな大きなヒープを確保するのをやめるのが一番です。

     

    どんなオンメモリDBなのかわかりませんが、

    状態が変わるたびに確保・解放するとか、

    テーブルごと、レコードごと、エントリごとに確保・解放するほうがいいでしょう。

     

    2008年4月20日 18:48
  •  れい さんからの引用

    仮想メモリ空間ではなく、ヒープの断片化です。

    newは.NETのマネージヒープ、AllocHGlobalはLocalAllocのエイリアスなので確かにヒープですね。

    大本となる仮想メモリ空間も、XPでは連続して空いてないんですよねぇ…。

    #Vistaでは結構連続して空いているようです。

     

    http://itpro.nikkeibp.co.jp/article/COLUMN/20070816/279802/?P=4

    このあたりで見るとフリーとなっている空間がばらけまくってますし。

    2008年4月20日 22:17
    モデレータ
  • みなさまお返事ありがとうございます。

     

    仮想メモリも連続しているわけではない、というのがよくわかりました。

    64ビットOSで解決するでしょうがヒープはフラグメントに弱いとのことで同様の不具合が起きる可能性を考慮し表単位に確保することにしました。

    固定長のページ単位で確保するのが無駄なく使えるかもしれませんが表の領域は連続しているのが都合がよいので上記のようにすることにしました。

     

    2008年4月22日 0:09
  • 便乗です。私も同じ悩みで困っています。

    最初に話しのあった、マシーンによってはのところですが、500M確保できないマシーンがあり原因不明です。その他のマシーンでは1Gでも確保できるのにです。AMDだからかなとか考えています。

    2008年4月29日 12:50
  • 回答済みの他の方のスレッドに便乗しないで下さい。

    目立ちません。

     

     ゼロ さんからの引用

    最初に話しのあった、マシーンによってはのところですが、500M確保できないマシーンがあり原因不明です。その他のマシーンでは1Gでも確保できるのにです。AMDだからかなとか考えています。

    OSや常駐ソフトによっては断片化が酷くなることがあります。

    CPUの種類は恐らく関係ないかと思います。

     

    常駐ソフトがそのプロセスに入り込み、メモリを食い荒らすようなことがあれば、連続で確保できる領域は減ります。

    連続した領域が確保できない前提でコードを組むべきでしょう。
    2008年4月30日 2:07
    モデレータ