Memory-01 プログラム中で可変のメモリを確保する
Q プログラム中で、確保するメモリサイズのコントロールがしたいです。
Dim **(10) As Byte では固定値になってしまいます。かといって、添え字の上限を省略することもできません…。
A HeapAlloc、HeapReAlloc、HeapFree関数を使います。
確保したメモリのサイズを求めたい場合はHeapSize関数を使います。
また、これらの関数を使用するためにGetProcessHeap関数を使います。
どう使う?
Dim Arg As DWordPtr
Arg=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,SizeOf(DWord)*50)
'この段階で DWord型のArg[0]〜Arg[49]が使える
Arg=HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,Arg,SizeOf(DWord)*100)
'この段階で DWord型のArg[0]〜Arg[99]が使える
HeapFree(GetProcessHeap(),0,Arg)
'この段階で メモリ解放完了
HeapAllocの第3引数・HeapReAllocの第4引数は、確保するメモリサイズをバイト単位で設定します。
これを使えば、プログラム中からサイズを変更することも可能です。
サイズを指定するとき「SizeOf(DWord)*50」「SizeOf(DWord)*100」としているのは、「DWord型4バイト」×「要素数50」という考え方によります[SizeOf(データ型) で要素のサイズが返される]。
要するに、データ型のサイズに、必要な要素数を掛けた数を指定すればよいのです。
また、Arg変数がDWordPtr型になっていますが、その他次の型も使えます。無論データ型のサイズは知っておく必要があります。要素サイズはSizeOf関数で取るようにすればとりあえず問題ありません。
BytePtr(1バイト/要素)・WordPtr(2バイト/要素)・SinglePtr(4バイト/要素)・DoublePtr(8バイト/要素)
HeapReAlloc関数は必ず使わなければならないわけではありません。
上のコードでは、プログラム中に一度決めたサイズを変更するのに使っていますが、
一度決めたら変更する必要がないときには、この関数は使わなくてもOKです。
そして、
HeapAlloc関数で確保したメモリは必ずHeapFree関数で解放しなければならない
という原則がありますのでこれを忘れないで下さい。
忘れるとメモリが解放されずに残り、パフォーマンス低下等の原因となりますのでご注意下さい。
使い方は、上を参考にして下さい。通常、「GetProcessHeap()」「HEAP_ZERO_MEMORY」をいじる必要はありません。
また、HeapFree関数の第2引数は必ず0になります。
Dim Arg As DWordPtr
Dim Size As DWord
Arg=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,SizeOf(DWord)*50)
'この段階で DWord型のArg[0]〜Arg[49]が使える
Size=HeapSize(GetProcessHeap(),0,Arg)/SizeOf(DWord)
MsgBox NULL,Str$(Size)
'この段階で メッセージボックスに要素数が表示される
HeapFree(GetProcessHeap(),0,Arg)
'この段階で メモリ解放完了
途中でサイズを取得したい場合はこのようにします。
なお、ここでも、HeapSizeの第1・第2引数は通常いじる必要はありません。
HeapSize関数は、指定したメモリの確保サイズをバイト単位で返します。
上のコードで、Sizeに結果を代入するときにSizeOf(DWord)で割っているのは、サイズを要素数に変換するためです。
全体のサイズをDWord型のサイズで割れば、要素数が出てくるのです。
そこで。
このコードでは、メッセージボックスには何と表示されるでしょうか。
答えは、通常「50」です。
ただし、実際には、指定より多くのメモリが確保されることがあり、その場合はこの限りではありません。
これらの関数は、高度なプログラムを組むときには欠かせない技ですので、是非覚えておきましょう。
※補足(2004/04/26)
AB Ver 3.07以降では、
「HeapAlloc(GetProcessHeap(),0,サイズ)」→「malloc(サイズ)」
「HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,サイズ)」→「calloc(サイズ)」
「HeapReAlloc(GetProcessHeap(),0,メモリ,サイズ)」→「realloc(メモリ,サイズ)」
「HeapFree(GetProcessHeap(),0,メモリ)」→「free(メモリ)」
のように簡単に書けるようになっています。もちろん従来の記述も使用出来ます。
簡単に書きたいところですが、「HeapSize」に対応する簡単な書き方がないため、このページでは引き続き従来通りの記述をすることにします。