BIOSでは4GB見えているメモリがWindows上では3GBほどになる原因と対処……

原因はさまざまなようですが、うちの場合はオンボードのビデオチップがVRAMとして使用することが原因のようでした。
BIOSの設定で、Video ConfigurationのIGD DVMT Memoryとかいう値とIGD Aperture Sizeとかいう値を小さくすると、Windowsの認識するメモリが増えました。

Windowsアプリで2GB以上のメモリを使うために必要なこと

メモリ4GBマシンがきたので。

実行環境の準備 - boot.iniに/3GBオプションを追加

Windows XPx86版では、アプリケーションの仮想アドレス空間が2GBに制限されています。4GBのうち半分はカーネルが使うようになっています。このためアプリケーションでは2GB以上のメモリを確保できません。この制限を回避するために、boot.iniに/3GBオプションを追加して、カーネルが3GB以降の1GBしか占有しないようにします。
物理メモリが3.2GBしか認識されない場合など、3GBもアプリケーションに割り当てられない場合は、/Uservaオプションにより2GB〜3GBの間で調節します。

アプリケーション側での対応 - 実行可能ファイルにIMAGE_FILE_LARGE_ADDRESS_AWAREフラグを追加

デフォルトの実行可能ファイルは2GBの仮想アドレス空間しか使えません。この制限を回避するためにIMAGE_FILE_LARGE_ADDRESS_AWAREフラグをヘッダ情報にセットします。このフラグがセットされているアプリケーションは3GBまでの仮想メモリが使えるようなメモリ配置になるようです。
方法としては、

  1. リンク時に/LARGEADDRESSAWAREオプションを追加
  2. Editbin.exeで設定

があります。
1は、VC++の場合、プロジェクトのプロパティからリンカのコマンドラインに追加します。2は、Editbin.exeというものがあるらしいですが、詳細は謎です。

テスト

てすとー

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

#define ALLOC_SIZE (1024 * 1024)

int main(void)
{
	void *p = NULL;
	size_t sum = 0;
	HANDLE hHeap = HeapCreate(0, 0, 0);
	if (hHeap == NULL) {
		perror("HeapCreate");
		return -1;
	}
	do {
		p = HeapAlloc(hHeap, 0, ALLOC_SIZE);
		sum += ALLOC_SIZE;
		printf("%uKB %p\n", sum / 1024, p);
	} while (p != NULL);

	return 0;
}
>cl memtest.c
Microsoft(R) 32-bit C/C++ Optimizing Compiler Version 15.00.21022.08 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

memtest.c
Microsoft (R) Incremental Linker Version 9.00.21022.08
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:memtest.exe
memtest.obj
>
> memtest
1024KB 00410020
2048KB 00520020
3072KB 00630020
....(略)
1965056KB 7FD40020
1966080KB 7FE50020
1967104KB 00000000
>

OSの設定で3GBまで使えるようにしていても、アプリケーション側での対応がないと2GBまでしか使えないようです。

> link /LARGEADDRESSAWARE memtest.obj
> memtest
1024KB BFAE0020
2048KB BF9D0020
3072KB BF8C0020
....(略)
2951168KB 001E0020
2952192KB 000D0020
2953216KB 00000000
>

リンカオプションで指定すると使えるようなりました。

OpenMPでの最適なスレッド数 (2)

CPU4コアマシンがきたので。

環境

CPU
Intel Core 2 Quad Q9550 @2.8GHz
RAM
1GB x 4

結果

// シングル/マルチ[スレッド数]: 完了時間ms: (素数数 @並列化がバグっていると変な値になる)
S   : 5078 (6541)
S   : 5079 (6541)
S   : 5093 (6541)
S   : 5078 (6541)
S   : 5079 (6541)
M2  : 3812 (6541)
M2  : 3813 (6541)
M2  : 3812 (6541)
M2  : 3813 (6541)
M2  : 3812 (6541)
M4  : 2219 (6541)
M4  : 2234 (6541)
M4  : 2219 (6541)
M4  : 2219 (6541)
M4  : 2234 (6541)
M8  : 1563 (6541)
M8  : 1578 (6541)
M8  : 1593 (6541)
M8  : 1610 (6541)
M8  : 1594 (6541)
M16 : 1312 (6541)
M16 : 1328 (6541)
M16 : 1375 (6541)
M16 : 1328 (6541)
M16 : 1344 (6541)
M32 : 1313 (6541)
M32 : 1296 (6541)
M32 : 1282 (6541)
M32 : 1312 (6541)
M32 : 1297 (6541)
M64 : 1281 (6541)
M64 : 1282 (6541)
M64 : 1281 (6541)
M64 : 1281 (6541)
M64 : 1281 (6541)

やっぱり多いほうが速い。Intelが書いたという噂のOpenCVのコードを見ていたら、OpenMPの処理でスレッド数=コア数にされていた。普通に考えるとそうなんだけど、この結果を見ると多くしてしまう。並列処理用のスレッド数=使用可能なプロセッサ数×8 にするようにした。

haartrainingで2GB以上のメモリを使用する方法

結論からいうとうまくいきませんでした。-memオプションで指定したメモリサイズの多くは1つのcvMatとして確保されるため、大きな連続したメモリ領域が必要になりますが、Windowsのヒープ管理でその領域を確保しきれないためです。知り合いのスーパーハッカーに聞いたところ、Windowsはそんな感じだという回答を得ました。
細かく確保してリンクリストで使うような設計にするといいんじゃないか…とか思いつつ、そこまではしません。
2.1GBまでは使えました。

2.1GBのメモリを使用するために変更する箇所

OpenCVはユーザ定義のメモリアロケータを指定できるように設計されていますが、ユーザ定義のメモリアロケータを呼び出す前にOpenCVで定義されているメモリサイズ上限のチェックして、それを超えている場合にエラーとしてはじいてしまいます。なぜなのかは不明なので危険な修正ですが、これをやめさせないと一度に1GB以上のメモリが確保できません。

// cxmisc.h: 81ふきん
/* maximum size of dynamic memory buffer.
   cvAlloc reports an error if a larger block is requested. */
#define  CV_MAX_ALLOC_SIZE  (((size_t)1 << (sizeof(size_t)*8-2)))

size_tが4バイトで、32bitマシンでは1GB以上は一度に確保できないようになっています。

#define  CV_MAX_ALLOC_SIZE  ULONG_MAX

ULONG_MAXにしてしまう。これはひどい。
他、リンカのオプションを追加してコンパイル→ Windowsアプリで2GB以上のメモリを使うために必要なこと - デー