プロが教える店舗&オフィスのセキュリティ対策術

Excel VBAでは大きな配列を生成しようとすると
メモリ不足でエラーが出るため、
どの程度のサイズまで作れるか試してみました。

Dim aaa() as Single
ReDim aaa(xxxxx)
というようにして定義しています。

Singleの配列を一つの場合には、
132813299
が上限であることが分かりました。

Singleの配列を2つの場合には、

132813299
130009804

が上限となりました。

Singleの配列を3つの場合には、

132813299
130009804
9

が上限となりました。
なぜか3つめは9より大きな配列を作ることができません。

それで配列サイズを小さくして試してみたところ


60000000
60000000
60000000
60000000
60000000
32000000

のようにして、3つの場合の合計よりも
大きなメモリを確保することができました。

つまり、合計のサイズに上限が決められているわけでもなく
配列一つ一つのサイズに上限が決められているわけでもないということが分かりました。

一体どういう法則でメモリサイズの上限が決定しているのでしょうか?

A 回答 (3件)

まず配列があるプログラム共通ですが、絶対的な配列の限界としてaaa(xxxxx)のxxxxxに限界があります


xxxxxはプログラム上変数として扱われており、変数が扱える数の限界が存在します
その限界が"132813299"だと思われます
変数の限界に関してはVBAならIntegerやLongなどを調べると記載されていますが、元から変数としての最大値が決定されているため、メモリにどれだけ余裕があろうとそれ以上取る事はできません
そのため配列を増やすと変数の上限は回避できます

ここからは完全に予測なりますが、前述のとおり配列の数を表すのにも変数が使われております
そして変数は型を宣言した時点で、通常はメモリが確保されています
特に動的配列は配列の数を変更する度に、使用するメモリサイズを宣言しなおしているため、動的配列として扱えてます
ここで問題となるのは事前に確保されるメモリの話で10個程度の配列を表すのに、"132813299"の数を表せる変数を使うのはメモリの無駄です
ですから無駄を避けるためには、小さ目の型でメモリを確保して置き、後から必要となった際に大きな型に変更する処理を行っていると思われます
この結果、配列の数を表す変数に大きくメモリサイズが消費されていない細かく分割した3番目のケースが最も効率よく配列を多く取れたとしても不自然ではありません

配列の大きさで変わる原因としては以上が考えられます
最もシステムのメモリ使用状態が同一であると仮定した上での話ですから、複数回試さないと確実とは言えません
    • good
    • 0

それはExcelというアプリケーションの構造に由来する話になるでしょう。



まず、どういった確保方法であれ、Windowsの32ビットアプリケーションで使用できるメモリの最大量(2GB)が絶対の上限として存在します。この2GBの中でVBAとExcel本体が使用するメモリの両方をやりくりするので、VBAが使用できる量は当然ながらもっと少なくなります。

またExcel本体側のメモリ使用状況によっては、空きメモリ領域が複数に分断されているかも知れません。例えばVBA側にメモリを1GB渡せるとしても、それは1つの固まりではなく、128MBや64MBなどの断片をかき集めたものかも知れないと言うことです。メモリの使用状況は予測が難しいため、最初から断片になることを見越して、あまり連続するメモリを取れなくしてある可能性も十分にありえます。配列は連続するメモリ領域に収まる分しか確保できないため、これが配列を小さくした方が、トータルではより多い配列を確保できる理由として考えられる点です。

メモリ使用状況起因だとすると、今出ている数値はどのPCでもそうなるとは限らないし、もしかすると今のそのPCでも毎回そうなる保証がないということになります。
    • good
    • 1

先に断っておきますが、私はVBAについての見識はほとんどありません。


ですのでうそ情報かもしれないことを念頭にお聞きください。
あくまでプログラム全般の法則として回答します。

まずさきに質問の答えとしては、
「合計のサイズに上限が決められている」だと思われます。



プログラムのメモリ確保にはスタックとヒープからの二種類の確保があります。
スタックから確保されるのは、関数のなかのローカル変数のメモリ割り当てになります。
今回のReDimの場合は、おそらくヒープからメモリ確保されているように思います。


ヒープからのメモリ確保というのは、ヒープというある程度大きいメモリから要求されたサイズの
メモリを割り当てることです。
今回のケースでの確保できる最大値というのは単純にヒープのサイズに依存するということです。

ですが、ヒープとは他からもメモリを確保されるため、
すでに使用されている分だけ確保できるメモリサイズは小さくなります。
また、メモリの確保と開放(ReDimでサイズを変えたり、不要なオブジェクトにnullを代入したり等)を行うことで
ヒープは分断化され確保できるメモリの最大値が変わってきます。
(おつかいのVBAのバージョンによっては、可能な限り確保する努力をしてくれるはずですが)


ヒープのサイズに関してですが、こちらはPCの環境(エクセルのバージョンやPCのスペック)に
依存するかと思いますので、ご自身のPCでメモリ確保できたものが、
別のPCではメモリを確保できないなどの現象もあるかもしれません。
不用意に巨大なメモリ確保を行うようなマクロは控えたほうがいいと思います。



ちなみに132813299の値を調べる際どのようなコードで調べられたでしょうか?

下記のようにループで検証した場合、ReDimの仕様上(新しいメモリへデータをコピーする可能性もある)
ヒープ上に以前の確保したメモリと、
これから新規に確保しようとしたメモリの二つが存在する可能性があり、
単純に最大サイズを検証することはできないと思います。
i = 1
Do
i = i + 1
ReDim aaa(i)
While
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています


このQ&Aを見た人がよく見るQ&A