トップ回答者
32ビットOSで2G近くのメモリを確保したい

質問
-
C#でオンメモリで動作するデータベースを作っています。
開発PCは3GBのメモリを搭載しています。
ユーザが使えるのは2Gまでと聞いています。勿論メモリ管理のオーバヘッドやプログラムをロードしているため全部を使えないことは理解しています。
byte[]bytes=new byte[1024*1024*1024];
と1GBのメモリを確保しようとするとOutOfMemoryExceptionが発生します。
マシンによっては800MBぐらいでもおきるようです。
内部ではfixedでunsafeコードで書いているため、実際にはMarshal.AllocHGlobal(int cb)でも良いのですが例外がおきるバイト数は変わりません。
もう少し大きく確保する方法はないでしょうか?
これは64ビットOSになっても同じような現象が起きるのでしょうか?
回答
-
和和和 さんからの引用 内部ではfixedでunsafeコードで書いているため、実際にはMarshal.AllocHGlobal(int cb)でも良いのですが例外がおきるバイト数は変わりません。
もう少し大きく確保する方法はないでしょうか?ありません。
仮想メモリ空間はハードディスクと同じで、断片化が起きます。
空き容量自体はある程度あっても、連続した領域がないんじゃないかと思われます。
解決策としては同時にメモリを必要としないように組み直すか、連続した領域とせず、細かい領域を確保するようにするしかないでしょう。
#もちろん、細かく確保しても空き容量には限界があります。
和和和 さんからの引用 これは64ビットOSになっても同じような現象が起きるのでしょうか?
64ビットアプリケーションとして組めば、連続した領域として確保できるかもしれませんが、64ビットOSでも32ビットアプリケーションとして実行される場合は無理でしょう。
#64ビットについては経験がないため、不確かです。 -
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なのかわかりませんが、
状態が変わるたびに確保・解放するとか、
テーブルごと、レコードごと、エントリごとに確保・解放するほうがいいでしょう。
すべての返信
-
和和和 さんからの引用 内部ではfixedでunsafeコードで書いているため、実際にはMarshal.AllocHGlobal(int cb)でも良いのですが例外がおきるバイト数は変わりません。
もう少し大きく確保する方法はないでしょうか?ありません。
仮想メモリ空間はハードディスクと同じで、断片化が起きます。
空き容量自体はある程度あっても、連続した領域がないんじゃないかと思われます。
解決策としては同時にメモリを必要としないように組み直すか、連続した領域とせず、細かい領域を確保するようにするしかないでしょう。
#もちろん、細かく確保しても空き容量には限界があります。
和和和 さんからの引用 これは64ビットOSになっても同じような現象が起きるのでしょうか?
64ビットアプリケーションとして組めば、連続した領域として確保できるかもしれませんが、64ビットOSでも32ビットアプリケーションとして実行される場合は無理でしょう。
#64ビットについては経験がないため、不確かです。 -
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なのかわかりませんが、
状態が変わるたびに確保・解放するとか、
テーブルごと、レコードごと、エントリごとに確保・解放するほうがいいでしょう。
-
れい さんからの引用 仮想メモリ空間ではなく、ヒープの断片化です。
newは.NETのマネージヒープ、AllocHGlobalはLocalAllocのエイリアスなので確かにヒープですね。
大本となる仮想メモリ空間も、XPでは連続して空いてないんですよねぇ…。
#Vistaでは結構連続して空いているようです。
http://itpro.nikkeibp.co.jp/article/COLUMN/20070816/279802/?P=4
このあたりで見るとフリーとなっている空間がばらけまくってますし。
-
回答済みの他の方のスレッドに便乗しないで下さい。
目立ちません。
ゼロ さんからの引用 最初に話しのあった、マシーンによってはのところですが、500M確保できないマシーンがあり原因不明です。その他のマシーンでは1Gでも確保できるのにです。AMDだからかなとか考えています。
OSや常駐ソフトによっては断片化が酷くなることがあります。
CPUの種類は恐らく関係ないかと思います。
常駐ソフトがそのプロセスに入り込み、メモリを食い荒らすようなことがあれば、連続で確保できる領域は減ります。
連続した領域が確保できない前提でコードを組むべきでしょう。