動的配列でメモリー不足の回避

解決


yTake  2022-07-31 06:06:52  No: 150318  IP: [192.*.*.*]

動的配列で別件です。
動的配列でメモリー不足に直面しています。

構造体の固定長配列をメンバーに持つ3次元の動的配列を取り扱うのですが、SetLengthのところで、
例外クラスEOutOfMemory(メッセージ 'メモリーが足りません')を送出しました。
が、発生します。

DELPHI XE6でFMX環境です。ターゲットは64ビットとしています。
主メモリは8GBです。

現在試している三次元の動的配列は、512x512x512です。配列要素がDouble変数一つであれば、メモリー不足は発生しませんでした。実際には、要素が構造体配列(固定長)になっている為、メモリー不足となっている様です。

動的配列はクラス変数の一つとして定義しています。
そのクラスを生成する際に必要に応じたサイズを定義するようにしています。


動的配列のメモリー不足対処をアドバイス頂ければと思います。

編集 削除
AAAAA  2022-08-01 16:41:56  No: 150323  IP: [192.*.*.*]

32ビットでコンパイルしてない?

編集 削除
yTake  2022-08-02 23:49:36  No: 150325  IP: [192.*.*.*]

AAAAAさん、コメントをありがとうございます。

最初にそれを疑いましたし、何度も確認しています。
64ビットでコンパイル・実行しています。

因みに、三次元をX,Y,Zとして、Zのデータを半分に減らすと、エラーなくSetLengthされます。

今一度、64ビットで実行しましたが、これまでと同様でした。

type
    RData = Record
     denc : Word;
       od : Single;
    norm1 : Single;
    disp1 : Byte;
     lvl1 : Word;
     dose : Single;
    norm2 : Single;
    disp2 : Byte;
     lvl2 : Word;
    End;
type
    RMTX  = Record
      ARY : Array [ 1 .. 6 ] of RData;
    End;
var
    ARY : Array of Array of Array of RMTX;
と定義しています。

実行部分は、
    SetLength( ARY, 512, 512, 256 );       <- OK 

    SetLength( ARY, 512, 512, 512 );       <-  NG
です。

当然ながら、RData構造体のメンバを半分に減らしても、SetLength可能です。


これはメモリー上の制約になるでしょうか?(実装メモリは8GB)
今回、作成しようとしている動的配列サイズが、512x512x512x6x28=22,548,578,304≒22GB
と実装メモリーの3倍近いです。
ただ、半分サイズの11GBでは問題ないので、単純に実装メモリーの問題でもなさそうに思います。
見当外れかもしれませんが、、、

編集 削除
mam  2022-08-03 01:39:44  No: 150326  IP: [192.*.*.*]

OSにはディスクキャッシュ機構がありますので、実メモリで足りない分はディスクにキャッシュされているからですね。
それでもキャッシュメモリを使っても(OSもつかいますので)足りないのでOut of memoryになってますね。

編集 削除
HFUKUSHI  2022-08-03 04:54:27  No: 150327  IP: [192.*.*.*]

ちょっと試してみました(Windows 10 Pro 21H2/x64/16GB/Delphi 11.1 Pro/VCL)
SetLength( ARY, 512, 512, 512 ); は成功して、この時のメモリ消費(private bytes)は21.4GBとなりました。
またRTXは168バイトなので、168x512x512x512=22,548,578,304バイト(=約21.4GB)でつじつまはあっています。
試しに倍のサイズ、つまり SetLength( ARY, 512, 512, 1024 ); を試してみましたが、こちらはOut of memoryでエラーになりますね。
ということで実装メモリ量に依存する、ということのように思われます。

編集 削除
AAAAA  2022-08-03 04:57:43  No: 150328  IP: [192.*.*.*]

ページングファイルサイズを
システム管理サイズ から カスタムサイズ に変更して
最大値あげたら 512 でも メモリ不足にならんかったよ

編集 削除
HFUKUSHI  2022-08-03 04:58:40  No: 150329  IP: [192.*.*.*]

なおWindowsの仮想メモリ(ページングファイルのサイズ)の管理は自動になっており、10797MBの割り当て、と表示されているので、
16GB+10GB=26GBまでは確保できたので前者は成功、後者は失敗になったものと推測されます。

編集 削除
AAAAA  2022-08-03 05:05:59  No: 150330  IP: [192.*.*.*]

うち8GB かなと思ってたら 16GB あって
256 OK で 512 NG だったんだけど
16GB あると 512 いけるんだということで
1024 で試しても メモリ不足にならんかったよ 

編集 削除
KONNOYA  2022-08-03 08:07:04  No: 150332  IP: [192.*.*.*]

掲示板の話の流れとは違うかもですが、
Record に packed を付けると少しだけ容量を稼げます。

RData = packed Record

packed無しのRDataレコードをSizeofしてみたら 28Bytes でしたが、
packed有りだと 24Bytes になりました。
デメリットもありますが…。

編集 削除
yTake  2022-08-03 09:51:53  No: 150333  IP: [192.*.*.*]

mamさん、HFUKUSHIさん、AAAAAさん、KONNOYAさん
ありがとうございました。
実装メモリーの影響の可能性と言う事で仮想メモリの設定をみてみました。
自動設定で、現在の設定が16250MB=16.25GBと言う事になり、Zが512(22GB)の時メモリー不足で、Zが256(11GB)ではエラーなしと言う事で辻褄が合いました。納得です。

実際の環境は16GBの予定です。HDDも十二分に余裕があります。事前に仮想メモリーを確認し、適切に設定すれば回避されそうです。


"Packed"宣言は使った事がありません。
機会があれば試してみたいと思います。


ありがとうございました。

編集 削除
Mr.XRAY  2022-08-07 01:37:36  No: 150342  IP: [192.*.*.*]

私もやってみました.
動的配列は 512 x 512 x 512 で,グローバル変数にしました.
この配列を 3 つ作成しました.
搭載メモリは 32 GB です.
結果,プロセスの使用メモリとしては 約 4 GB となりました.非常に時間がかかりました.
配列を 4 つにするとメモリ不足になりました.

変数を確保,操作する際,特に配列や TStringList 等は,作業用に多くのメモリを使用します.
今回は物理メモリ 32 GB のほとんどと,仮想メモリも 54 GB 以上使用していました.
これが実際に必要なメモリ量かも知れません.
動的配列はポインタですから,4 GB というのは,ポインタとしての確保量かも知れません.

配列要素に,実際にデータを格納すると,その分のメモリが必要です.
多分,配列としては確保できても,実用にはならないのではないか,思っています ( 未確認です ).
  
      
ところで,現在の気象情報は,位置として,緯度,経度,高度を使用する 3 次元データです.
スーパーコンピュータを使用していますが,
スーパーコンピュータ 富岳の場合,そのメモリは 4.85 PiB ( ペビバイト ) です.
1 PiB は 2 の 50 乗 バイト ( = 1,125,899,906,842,624 バイト ) です.
これなら,今回の配列も全く問題ありませんね.😀
ただし,使用可能なコンパイラは Fortran, C, C++ 等です.Delphi はありません.
 
         
昔,まだ PC のメモリが少ない頃,2 次元配列を使用する計算で,
行単位でディスクから配列データを読み書きして計算したことがあります.
気が遠くなるほど時間がかかりました .
コンピュータ関係の雑誌に,巨大行列 (配列) の計算方法の記事があり,それを参考にしました.
  

編集 削除
Mr.XRAY  2022-08-07 03:37:20  No: 150343  IP: [192.*.*.*]

失礼しました.動作確認は以下です.
Windows 10 ビルド 19043 + Delphi XE5(UP2) Pro VCL-64

編集 削除
Mr.XRAY  2022-08-08 04:38:12  No: 150344  IP: [192.*.*.*]

仮想メモリを,カスタムサイズで 100 GB にしたら 4 つ分のメモリを確保できました.
物理メモリの 32 GB はほとんど全て,仮想メモリは約 96 GB 使用という状態になりました.

> 多分,配列としては確保できても,実用にはならないのではないか,思っています ( 未確認です ). 

配列要素の多くが仮想メモリに置かれます.つまり,ディスクへのアクセスとなります.
物理メモリとは違い,処理に時間がかかるということになります.
最近の HDD は高速ですから,なんとか実用に耐えるかも知れません.
SSD なら申し分ないのかも知れません.

編集 削除
HFUKUSHI  2022-08-08 07:41:15  No: 150345  IP: [192.*.*.*]

もし512x512x512の全ての要素を使うのではなく、一部の要素だけに値が入るのであれば、スパース配列(疎配列)という実装もありかとは思います。
https://ja.wikipedia.org/wiki/%E7%96%8E%E8%A1%8C%E5%88%97

編集 削除