C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[9]: 利用可能なメモリーサイズを調べる方法


(過去ログ 163 を表示中)

[トピック内 10 記事 (1 - 10 表示)]  << 0 >>

■94426 / inTopicNo.1)  利用可能なメモリーサイズを調べる方法
  
□投稿者/ ぱそ (1回)-(2020/04/11(Sat) 15:55:09)

分類:[.NET 全般] 

VB.NETに関する質問です。

32bit Windows10で動作するプログラムを開発する必要があるのですが、
一つのプログラム当たり使えるメモリー容量には2GBの制限があります。

プログラムを起動中に後、何GB使えるか調べたいのですが
どのようなコードを使えば調べられますか?

一応、調べてみたのですが見つかりませんでした。


引用返信 編集キー/
■94427 / inTopicNo.2)  Re[1]: 利用可能なメモリーサイズを調べる方法
□投稿者/ 774RR (780回)-(2020/04/11(Sat) 16:10:16)
Win32 で max 2GiB ってのは確かだけど、調べてどうするの?
分断化された小さな空き容量の総和 と
連続して確保できる空き容量 とは異なり、
前者が 1GiB あっても後者は 256MiB なんてのはよくある話で、メモリの使い方によっては後者しか意味がなかったりする。

メモリ空き容量が知りたいわけではなくて、本当に解決したい問題は全く別なのでは?
XY 問題とかラクダと青年とかそういう話になってない?
引用返信 編集キー/
■94428 / inTopicNo.3)  Re[2]: 利用可能なメモリーサイズを調べる方法
□投稿者/ ぱそ (2回)-(2020/04/11(Sat) 17:10:37)
やりたいことはこういうことです。

以下のようにforループで二次元配列を生成していくのですが、
MaxNumをいくつまで上げられるのか処理の前に決めておきたいわけです。

Dim Array(MaxNum)(,) As Single


For i = 1 To MaxNum

Rdim Array(i)(1000,1000)

処理内容

Next

処理の途中で別のプログラムが動作する可能性があるので、
使用可能なメモリーの半分程度に設定しておくつもりです
どのようにして調べれば良いですか?

また、以上にようにして確保されるメモリーは
分断化された小さな空き容量の総和 と
連続して確保できる空き容量
のどちらに相当しますか?
引用返信 編集キー/
■94429 / inTopicNo.4)  Re[3]: 利用可能なメモリーサイズを調べる方法
□投稿者/ 774RR (781回)-(2020/04/11(Sat) 19:29:00)
> 使用可能なメモリーの半分程度に設定しておくつもりです
えっと、そういう話が出てくるということは
・当該マシンにおける全プロセスが使うことができるメモリ容量 と
・1プロセスが使うことができるプロセス内仮想アドレス空間 とを
混ぜてしまっていて、混乱したままだと技術論的な話が通じないっす。

たいていの「メモリ容量の調査」記事は前者
https://dobon.net/vb/dotnet/system/wmi_os.html
32bit CPU + 32bit Windows の場合は PAE 有効である場合に max 3GiB 無効なら max 2GiB
64bit CPU + 32bit Windows の場合は max 4GiB
64bit CPU + 64bit Windows の場合は max 2TiB

だけどあなたが気にするべきはこっちぢゃなくて後者で
64bit Windows でも x86 アプリなら、1つのアプリが使えるメモリ=仮想アドレス空間は 2GiB
この 2GiB 中に EXE や DLL がロードされる都合上、一般的に x86 アプリがデータに使えるのは 1GiB 無いのが普通っす。
オイラが言っている「分断化された」うんぬんもプロセス内仮想アドレス空間の使用未使用の話。

配列は「連続したメモリ」を取る代物なので提示コードのように Redim を繰り返すのは悪手で、
最悪パターン時、元領域 512MiB + `新領域 512MiB となってメモリ空間が 1GiB 空いていても 512MiB しか使えないっす。

で、こっちの「プロセス内最大連続空きメモリ空間」を調べる方法は無いっつか、
配列を取って、取れたならそれが最大連続空きメモリ空間っす。
ただし、この最大連続空きメモリ空間を全部確保することでページファイルも使うことになったら
スラッシングして性能は出なくなる可能性が高いっすよ。

案件が「スラッシングしてでも計算できること」なのか「スラッシングしない範囲で計算したい」のかで話はちがってきて
後者なら先の dobon さんとこの AvailablePhysicalMemory を使うといいかもしれない。
オイラなら max(AvailablePhysicalMemory, 1GiB) を使ってみるかな・・・

# 大量メモリを使う富豪プログラムがしたいなら、いまどきは 64bit マシンを用意すべき
# 32bit マシンで実行する必然があるなら設計当初段階からメモリの節約を考えるべし
引用返信 編集キー/
■94430 / inTopicNo.5)  Re[4]: 利用可能なメモリーサイズを調べる方法
□投稿者/ とっちゃん (668回)-(2020/04/11(Sat) 19:52:05)
No94428 (ぱそ さん) に返信

問題の本質のほうは 774RR さんが書いているので、まずはそちらをお読みください。

<<抜粋>>
> Dim Array(MaxNum)(,) As Single
> For i = 1 To MaxNum
> Rdim Array(i)(1000,1000)
> Next
>
> また、以上にようにして確保されるメモリーは
> 分断化された小さな空き容量の総和 と
> 連続して確保できる空き容量
> のどちらに相当しますか?

Array()(,) という定義は Signle 型の2次元配列(.NET の場合はヒープ上に動的に確保する)の
ジャグ配列(C的に言えばポインタ配列)なので、連続領域となるのは
4x1000x1000、必要なサイズはそれ× MaxNum 個です。

引用返信 編集キー/
■94431 / inTopicNo.6)  Re[5]: 利用可能なメモリーサイズを調べる方法
□投稿者/ ぱそ (3回)-(2020/04/11(Sat) 22:46:27)
詳細なご説明ありがとうございます。


> だけどあなたが気にするべきはこっちぢゃなくて後者で
> 64bit Windows でも x86 アプリなら、1つのアプリが使えるメモリ=仮想アドレス空間は 2GiB

質問文でお聞きした通り、2GiBが上限なのは分かっています。


> この 2GiB 中に EXE や DLL がロードされる都合上、一般的に x86 アプリがデータに使えるのは 1GiB 無いのが普通っす。
> オイラが言っている「分断化された」うんぬんもプロセス内仮想アドレス空間の使用未使用の話。

ここをお聞きしたかったのですが、
EXEファイルのサイズは1MB程度でDLLは一切使用していません。
となると、2GiBまるごと使えるのでしょうか?
ここがどの程度まで使えるかを調べるためのコードを知りたいのです






> 配列は「連続したメモリ」を取る代物なので提示コードのように Redim を繰り返すのは悪手で、
> 最悪パターン時、元領域 512MiB + `新領域 512MiB となってメモリ空間が 1GiB 空いていても 512MiB しか使えないっす。


ここは理解できていません。
Redimを繰り返すと半分のメモリー容量しか使えないのはなぜですか?
繰り返すのではなく
Dim Array(MaxNum,1000,1000)
のようにして、一度に宣言すればまるごと使えるという意味ですか?
もっと良い方法があればお教えください。



> 案件が「スラッシングしてでも計算できること」なのか「スラッシングしない範囲で計算したい」のかで話はちがってきて

スラッシングしない範囲で計算したいというのがご回答です。



> 後者なら先の dobon さんとこの AvailablePhysicalMemory を使うといいかもしれない。
> オイラなら max(AvailablePhysicalMemory, 1GiB) を使ってみるかな・・・

AvailablePhysicalMemoryは既に使っているのですが、
上で述べた通りコレはOS全体の3 or 4GBを上限とした使用可能なメモリー容量であって
いま知りたい起動しているプログラムのメモリ容量ではないので、
大丈夫かと心配になっています。


引用返信 編集キー/
■94432 / inTopicNo.7)  Re[6]: 利用可能なメモリーサイズを調べる方法
□投稿者/ 774RR (782回)-(2020/04/12(Sun) 06:47:15)
あなたのソースコード上、明示的に DLL を使っていなくても Windows / .NET Framework が暗黙に DLL をロードしているので
(デバッガ画面になんちゃら DLL をロードしましたって表示が出るの見たことありますよね?)
データ領域として 2GiB をまるまる使うことはまず絶対にできないです。
英語版 Windows で暗黙ロードされる DLL を最小になるよう native x86 アプリを工夫して 1.5GiB 使えたら御の字
極東 Windows では日本語/中国語 IME などがほぼ必須な関係上 1.0GiB 程度に減っちゃう可能性が高いです。
manage アプリではもっと小さくなるとみてください (gc があるので分断化の影響は少なくなりますが最大容量は減る)
なので AvailablePhysicalMemory によらず x86 アプリが使えるデータ領域は 1GiB と見積もるのがセオリーです。

Redim は C でいうところの realloc に相当し、元配列を同じアドレスのまま拡張できない場合には
元配列とは別のアドレスに新配列を取り、値をコピーし、元配列を処分する( gc があってもこのロジックは変わらない)
必要があるので一時的には元配列の2倍以上のメモリ容量が必要です。

> 一度に宣言すればまるごと使えるという意味ですか?
はい

この話、物理メモリ 256MiB のマシンでは 256MiB 未満を使いたい、物理メモリ 4GiB では 1GiB を使いたいってことだと
最初から思ってたわけだけど、物理メモリ 256MiB マシンとかは最初から相手にしてないわけ?
(手元に未使用な20年前のマシンがあるので、計算をさせてほおっておこうとかいうストーリーだと思ってた)
物理メモリ 256MiB なら AvailablePhysicalMemory も 256MiB になるはず
物理メモリ 4GiB でも x86 アプリでデータ領域として使えるメモリは 1GiB 程度となるのが経験則
なので max(AvailablePhysicalMemory, 1GiB) を提案したわけだけど。

引用返信 編集キー/
■94433 / inTopicNo.8)  Re[7]: 利用可能なメモリーサイズを調べる方法
□投稿者/ Azulean (1138回)-(2020/04/12(Sun) 08:27:16)
考え方としてはこういうものかなぁ…。
https://qiita.com/kattoshi/items/f6f060729227f41f89b0

ただ、この戦略は個人的にお勧めはしないですね。
初期の小さなプロジェクトでは問題なかったとしても、そのアルゴリズムを流用したり、プロジェクトが肥大化したりして、メモリ不足が頻発するなど、トラブルの種となりそうであるため。

個人的には、メモリを多く使いたいなら x64 化を提案しておきたいところ。
Intel を始め、多くのドライバーが 32bit Windows 10 のサポートを提供しなくなっているので、32bit Windows のシェアは下がってきつつあるはず…。
引用返信 編集キー/
■94435 / inTopicNo.9)  Re[8]: 利用可能なメモリーサイズを調べる方法
□投稿者/ ぱそ (4回)-(2020/04/12(Sun) 15:33:33)

> あなたのソースコード上、明示的に DLL を使っていなくても Windows / .NET Framework が暗黙に DLL をロードしているので
> (デバッガ画面になんちゃら DLL をロードしましたって表示が出るの見たことありますよね?)


それは分かっているのですが、
IMEなどの共通のアプリも一つのプロセスに必要なメモリー量にカウントされるのでしょうか?


一つのプロセスで最低1GB必要なのだとすると
3つ以上のプロセスを起動すると3GBを超えてしまい、
メモリーの最大容量を超えてしまいますが、
これはどう考えれば良いですか?


> Redim は C でいうところの realloc に相当し、元配列を同じアドレスのまま拡張できない場合には
> 元配列とは別のアドレスに新配列を取り、値をコピーし、元配列を処分する( gc があってもこのロジックは変わらない)
> 必要があるので一時的には元配列の2倍以上のメモリ容量が必要です。

拡張できない場合には、ということは、Redimにおいて毎回二倍のメモリ量が必要というわけではなく
必要ない場合があれば、必要ない場合もあるということですか?
また、コピーするということは、拡張できない場合には、拡張できる場合と比べて
少し時間がかかるということを意味しますか?


> 物理メモリ 256MiB なら AvailablePhysicalMemory も 256MiB になるはず
> 物理メモリ 4GiB でも x86 アプリでデータ領域として使えるメモリは 1GiB 程度となるのが経験則

上の説明では、一つのプロセスは最低でも1GBは使用しているので、
実質使えるのは残りの1GBしかないという話でしたよね?
となると、そもそも256MBしかメモリーを積んでいない場合には、
いくつかメモリーを使用しているのでしょうか?

半分の128MBと考えて良いですか?

引用返信 編集キー/
■94436 / inTopicNo.10)  Re[9]: 利用可能なメモリーサイズを調べる方法
□投稿者/ Azulean (1139回)-(2020/04/12(Sun) 16:48:27)
2020/04/12(Sun) 16:52:08 編集(投稿者)

No94435 (ぱそ さん) に返信
> それは分かっているのですが、
> IMEなどの共通のアプリも一つのプロセスに必要なメモリー量にカウントされるのでしょうか?
厳密に言えば、IME は「アプリ」や「プロセス」としても存在するが、あなたのプロセス内にも DLL として読み込まれる。
このほか、ウィルス対策ソフトやユーティリティ系のソフトの DLL があなたのプロセスに読み込まれることになります。


> 一つのプロセスで最低1GB必要なのだとすると
> 3つ以上のプロセスを起動すると3GBを超えてしまい、
> メモリーの最大容量を超えてしまいますが、
> これはどう考えれば良いですか?
2GB(や 3GB)の限界は、プロセスごとの上限です。
システム全体の制限ではありません。

また、物理メモリを超えた領域については、ハードディスクへのスワップが用いられますので、物理メモリの限界が即座にメモリ確保の限界ではありません。
もちろん、スワップが多用されるようなシステム・プログラムでは非常に低速になりますので、過剰な期待は厳禁です。


> 拡張できない場合には、ということは、Redimにおいて毎回二倍のメモリ量が必要というわけではなく
> 必要ない場合があれば、必要ない場合もあるということですか?
> また、コピーするということは、拡張できない場合には、拡張できる場合と比べて
> 少し時間がかかるということを意味しますか?
この辺を理解したいなら、ヒープの概念も学ぶべきでしょうね…。
真に理解したいのであれば、質問ベースではなく、CLR がどのようにメモリを確保するかといった技術資料を探して読み込むことが必要でしょう。


> 上の説明では、一つのプロセスは最低でも1GBは使用しているので、
> 実質使えるのは残りの1GBしかないという話でしたよね?
> となると、そもそも256MBしかメモリーを積んでいない場合には、
> いくつかメモリーを使用しているのでしょうか?
「2GB のうち、1GB ぐらいしか利用できないこと」と、「1 つのプロセスが最低でも 1GB 使っていること」はイコールではありません。

多くの場合、プロセスのアドレス空間は断片化しています。
「連続して確保できる量の目安は 1GB ぐらいだろう」であり、「常に 1GB 占有されている」ということではありません。



メモリは必要なときに必要なだけ確保することを前提としてください。
あらかじめ確保しておくことを考えるなら、ヒープやプロセスのメモリ空間に関する知識を深め、あなたの前提・制約において最適なものを考え出してください。
事前確保の戦略において、すべての環境に取って最良の選択なんてないので…。

-----
脱線気味ですが、なぜ事前に確保するの?という疑問を抱きます。
メモリの断片化を知らない段階では、事前に確保する戦略を採る理由が予想できませんでした。
やらなくても良いことをやろうとしていないかを気にしています。
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -