LARGEADDRESSAWARE

 

このページで触れているのは 32bit アプリを作成する場合に限定した話とテクニックについてです。

Win7 64bit(WoW64) ではプロセスあたり最大4GBを使用できます。
Win7 32bit ではプロセスあたり最大2GBを使用できます。
これはMicrosoftの正式見解です。

ただし、最大4GBで動作するには若干条件があるようです。
「IMAGE_FILE_LARGE_ADDRESS_AWARE 指定あり」でコンパイルした32bit exe だと最大4GB ということらしいです。

 

Visual Studio 上で設定する場合、リンカーから "大きいサイズのアドレス" で "はい(/LARGEADDRESSAWARE)" を設定します。

リンカーオプション

 

.NET(C#)の場合は Visual Studio 上のコンパイルオプションで指定はできず、editbin という外部ツールでこのフラグを後付けします。

editbin /LARGEADDRESSAWARE $(TargetPath)

LARGEADDRESSAWAREがついたかどうかの確認は、

dumpbin /headers $(TargetPath)

を実行して、

Application can handle large (>2GB) addresses

と表示されればOKです。

 

評価環境やコンパイル環境などの情報があまり記載されていないので、いずれにせよテストプログラム等による確認が必要。ひょっとすると比較的新しい開発環境ではデフォルトで上記オプションが有効化されていたりする場合もあると思います。

Visual Studio と C++ を使ってテストプログラムを作成してみたので、以下結果報告。
評価環境は以下の通り。

 

[環境]

開発環境 : Visual Studio 2022 pro., Version 17.5.1
  Visual Studio 2012  
OS : Windows11 home, 22H2
  Windows8 64bit  

 

 

1. x86 + LARGEADDRESSAWARE

こんなテストプログラムを作成。
作成するプログラム画面

 

約3.5GBのメモリを確保できました。"LARGEADDRESSAWARE"無しだと1.3GBぐらいまでしかメモリ確保できませんでした。
32bit 実行結果

 

2. x64

同様に x64 コンパイルして実験。上限を確認してもきりがないので、メモリ取得サイズは8GBにて。
64bit 実行結果

 

x64 だとやっぱり8GBなんて楽勝に取得できるみたいです。
64bit 実行結果

 

3. サンプルプログラム

上記のテストプログラムを以下からダウンロードできるようにしておきます。
プログラムはWin32プロジェクトとして作成していますので、Visual Studio 以外の環境へも移植が容易でしょう。 
ダウンロード

 

補足説明1:
なお、ソースプログラム中にある以下の記述は Windows XP 以降のコモンコントロールを使用するための記述です。マニュフェストでコモンコントロールのバージョン情報を記載する必要があるそうで、VS2005から加わった #pragma の記述だそうです。コモンコントロールのバージョンを 6.0.0.0 で指定します。このマニュフェストが無いとビジュアル的に古い感じのダイアログになってしまいます。

#if defined _M_IX86 
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") 
#elif defined _M_IA64 
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"") 
#elif defined _M_X64 
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"") 
#else 
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") 
#endif 

 

補足説明2:
マニュフェストファイルを別ファイル指定してコンパイルしています。実行ファイルと同じ場所にあるマニュフェストファイルを消さないでください。

補足説明3:
(謎)x86の実行ファイルをデスクトップで実行した場合に、何故か上記補足説明1で有効化したはずのビジュアルスタイルが有効化されずに古いダイアログ形式で表示されました。謎です。

 

["test_LargeWare.cpp "]

#include "stdafx.h"
#include "testLargeWare.h"

using namespace std;

#if defined _M_IX86 
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") 
#elif defined _M_IA64 
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"") 
#elif defined _M_X64 
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"") 
#else 
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") 
#endif 

// #define
#define WM_ALLOC_COMPLETED  (WM_USER+1)     // ユーザー定義メッセージ

// グローバル変数:
HINSTANCE       hInst;

// このコード モジュールに含まれる関数の宣言を転送します
BOOL CALLBACK DlgProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp);


int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPTSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    hInst = hInstance;

    DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, (DLGPROC)DlgProc);
    return 0;
}


void AllocMemory( HWND hWnd, vector<char*>& vBuffer, unsigned int bytes, int& allocsize )
{
    bool        bSuccess = true;

    // バッファをクリア
    {
        for ( size_t i=0; i<vBuffer.size(); ++i){
            delete[] vBuffer[i];
            vBuffer[0] = nullptr;
        }
        vBuffer.clear();
        vBuffer.resize(0);
        vector<char*>(vBuffer).swap(vBuffer);
        allocsize = 0;
    }

    // メモリを取得
    {
        int         j;
        int         k;
        const int   allocBytesUnit = 128 ;  // 128MB単位でメモリを確保

        // allocBytesUnit 単位で確保する個数と余りを算出する
        j = bytes / allocBytesUnit;
        k = bytes - ( j * allocBytesUnit );

        try{
            // allocBytesUnit 単位でメモリ領域を確保する
            for ( int i = 0; i < j; i++ ) {
                char *p = new char[ allocBytesUnit * 1024 * 1024 ];
                if ( nullptr == p ){
                    break;
                }

                for ( int l = 0; l < k * 1024 * 1024; l++ ){
                  ( (char*)p )[l] = 0;
                }
                vBuffer.push_back( p );
                allocsize += allocBytesUnit;
            }

            // 余りの分を確保する
            if ( k > 0 ) {
                char *p = new char[ k * 1024 * 1024 ];
                if ( nullptr != p ) {
                    for ( int l = 0; l < k * 1024 * 1024; l++ ){
                        ( (char*)p )[l] = 0;
                    }
                    vBuffer.push_back( p );
                    allocsize += k;
                }
            }
        }
        catch( bad_alloc ){
            _RPTW0(_CRT_WARN, "\"Bad alloc\" happen.");
            bSuccess = false;
        }
    }
    
    PostMessage( hWnd, WM_COMMAND, WM_ALLOC_COMPLETED, (LPARAM)bSuccess );
}


//
//  関数: DlgProc(HWND, UINT, WPARAM, LPARAM)
//
//  目的:  メイン ウィンドウのメッセージを処理します。
//
BOOL CALLBACK DlgProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
    static vector<char*>    vBuffer;
    static unsigned int     bytes ;
    static int              allocsize = 0 ;
    static thread           thr_AllocMemory;


    switch (msg) {
    case WM_DESTROY:
        if ( thr_AllocMemory.joinable() ){
            thr_AllocMemory.join();
        }
        break ;

    case WM_CLOSE:
        if (MessageBox(
            hWnd,
            (LPCTSTR)_T("プログラムを終了してよろしいですか?"),
            (LPCTSTR)_T("終了確認"),
            MB_YESNO | MB_ICONQUESTION) == IDNO)
        {
            // プログラムを終了しない
            return FALSE;
        }

        // プログラムを終了する
        EndDialog(hWnd, IDOK);
        return TRUE ;

    case WM_INITDIALOG:
        HICON   hIcon;
        hIcon = (HICON)LoadImage( hInst, MAKEINTRESOURCE(IDI_ICON1), IMAGE_ICON, 256, 256, 0);
        SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);

        SetDlgItemText( hWnd, IDC_MESSAGE, L"" );
        return TRUE;

    case WM_COMMAND:
        switch (GET_WM_COMMAND_ID(wp, lp)) {
        case IDOK:
            SendMessage( hWnd, WM_CLOSE, 0, 0 );
            return TRUE;

        case IDC_BUTTON1:
            {

                // 取得するバイト数をエディットボックスから取得
                {
                    bytes = GetDlgItemInt( hWnd, IDC_EDIT1, NULL, FALSE);
                    _RPTW1(_CRT_WARN, L"%d\n", bytes);
                }

                // メモリ取得実行
                {
                    thread t( &AllocMemory, hWnd, std::ref(vBuffer), bytes, std::ref(allocsize));
                    thr_AllocMemory.swap(t);
                }

                SetDlgItemText( hWnd, IDC_MESSAGE, L"メモリ取得中..." );
                EnableWindow( GetDlgItem( hWnd, IDC_BUTTON1), false );
                EnableWindow( GetDlgItem( hWnd, IDC_EDIT1), false );
            }
            break;

        case WM_ALLOC_COMPLETED:
            SetDlgItemText( hWnd, IDC_EDIT1, L"");
            SetDlgItemText( hWnd, IDC_MESSAGE, L"" );
            EnableWindow( GetDlgItem( hWnd, IDC_BUTTON1), true );
            EnableWindow( GetDlgItem( hWnd, IDC_EDIT1), true );

            thr_AllocMemory.join();

            _RPTW0( _CRT_WARN, L"Complete memory alloc.\n");
            // 結果を表示しておく
            {
                std::wstringstream  str;
                bool    bSuccess = (bool)lp;

                if ( !bSuccess ){
                    str << L"メモリ取得を失敗しました。\n";
                }
                str << L"要求されたバイト数:" << bytes << " (MB)\n" << L"確保したバイト数" << allocsize << " (MB)";

                MessageBox( hWnd,  str.str().c_str(), L"結果", MB_OK|MB_ICONINFORMATION );
            }
            break;

        default:
            break;
        }
        break;

    default:
        break;
    }

    return FALSE;
}

 

 

ライセンス

本ページの情報は、特記無い限り下記 MIT ライセンスで提供されます。

The MIT License (MIT)

Copyright 2013 Kinoshita Hidetoshi

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

 

 

参考

 


 

変更履歴

2023-03-09 - ページデザイン刷新
    "Visual Studio 2022" を評価環境および説明へ追加
    ソースコード紹介を追加
2013-05-12 - 新規作成

 

Programming Items トップページ

プライバシーポリシー