静的に確保するメモリ サイズが大きいアプリケーションの実行時のエラーについて
こんにちは、Visual Studio サポート チームです。
今回は、巨大なサイズのメモリを静的に確保するようなアプリケーションを実行した場合に発生するエラーについてご案内します。エラー自体は Windows OS の想定された動作に基づくものですが、Visual C++ でのビルド時に予め問題を検出できないケースもあり、注意が必要となります。
OS によるフォーマット チェックで検出されるエラーについて
Windows OS では、アプリケーションを起動する際、事前に対象ファイルのフォーマットのチェックを行い、静的に確保されているメモリのサイズが大きすぎる場合に、アプリケーションの実行を制限します。
このサイズの上限は、後述の Visual C++ のリンカーが制限している 2GB とは完全に一致しておらず、アプリケーションのビルド時にエラーが検出されなかった場合でも、アプリケーションを実行できない場合があるのでご注意ください。
Windows OS によってアプリケーション実行時に検知されたエラーは STATUS_INVALID_IMAGE_FORMAT (0xC000007B) エラーとして OS 内部で通知され、以下のように「有効な Win32 アプリケーションではない」または「このアプリはお使いの PC では実行できません」といったエラー メッセージが表示されます。
サンプル コード
以下の Visual C++ コードを Visual Studio でコンパイルして実行することで、上記エラーを確認することができます。
#include<stdio.h>
static char c1[1073741824];
static char c2[1000000000];
int main(){
c1[10] = '*';
c2[12] = '-';
printf("c1[10] = %c\n", c1[10]);
printf("c2[12] = %c\n", c2[12]);
return 0;
}
Visual C++ のリンカーで設定されている上限値について
Visual C++ では、コンパイラーやリンカーを個別に実行して実行可能ファイル (EXE、DLL など) を作成することが可能です。 ここで、リンカーではアプリケーションが静的に確保するメモリ領域が 2GB を超過するようなコードに対してはリンカー エラー (LNK1248) を返します。リンカー エラーの詳細についてはMSDN ライブラリのドキュメントを参照してください。
(参考 1) 割り当て可能な仮想アドレス空間のサイズについて
32bit Windows OS では、仮想アドレス領域内のユーザー空間に 2GB のメモリ領域を確保しますが、アプリケーションを実行する際には、メモリ上にスタック領域の確保や exe および dll の実行コードの配置などを行うため、実際に確保可能なサイズは 2GB より少ないサイズとなります。
また、64bit Windows OS で 64bit アプリケーションを実行する場合は、ユーザー領域に 2GB 以上のメモリ領域を使用可能ですが、イメージ ファイルの実行時に確保しようとするメモリサイズのチェックロジックは、 32bit Windows OS と同じもので、同様の動作となりますのでご注意ください。
32bit アプリケーション および 64bit アプリケーションで巨大なサイズのメモリを使用する場合、一般的には動的にメモリを確保する方法を推奨しています。
(参考 2) DLL やサービス アプリケーションの場合
実行可能ファイル (EXE) の実行時に発生するエラーは上記のとおりですが、同じような内容を含む DLL を LoadLibrary 関数などで動的にロードしようとした場合は、実行時のメモリ使用状況により、以下のエラーが発生する可能性があります。
- ERROR_BAD_EXE_FORMAT(193)
- ERROR_COMMITMENT_LIMIT (1455)
- ERROR_NOT_ENOUGH_MEMORY (8)
また、このようなアプリケーションを、サービスとして実行した場合は、サービスの起動時に「エラー 193」により失敗します。
たとえば、コマンドプロンプト上で「sc start <サービス名>」を実行した際のエラーは以下のように表示されます。
「[SC] StartService はエラー 193 により失敗しました。」
また、管理ツールの「サービス」から手動で起動しようとすると、以下のようなエラーメッセージが表示されます。
上記のようなエラーが発生する場合も、ここでご案内した状況である可能性がありますので、確保するメモリのサイズを注意してみる、静的に確保されているメモリを動的に確保するようにする、などを試してみてください。