C / C ++言語の標準のアロケーターnew / delete / malloc / freeがスピードで輝かないことは秘密ではありません。 もちろん、それはすべて実装に依存しますが、Microsoftからそれについて話すならば、これは事実です。 さらに、アロケーターの標準実装には、別の致命的な欠陥-メモリの断片化があります。 プログラムが頻繁に割り当て/割り当て解除される場合、数時間後にメモリ不足のためにプログラムがクラッシュしますが、まだ十分な空きメモリがあります-アロケータプールでの断片化の結果、十分な空き領域が残っていないことがわかります。 (これは、偶然にも、私が直接関与していたプロジェクトの1つで発生した絶対に現実的なケースです。)
幸いなことに、これらの欠点の両方に欠けているアロケーターがあります。 私は一度にdlmallocを試しました。それ以来、常にプロジェクトで使用しています。
dlmallocをVisual Studio C / C ++のプロジェクトに接続する方法を共有したいと思います。
私が使用する方法は、プログラムでのみ発生する可能性のあるすべての割り当てに代替アロケーターを使用できるという点で注目に値します。 はい、簡単な方法(つまり、malloc呼び出しをdlmallocに置き換える)では、この効果は得られません。 たとえば、mallocを使用してメモリを割り当てるサードパーティライブラリを接続しました。 さらに、stdlibからの標準関数へのいくつかの呼び出しもmalloc関数を使用してメモリを割り当てますが、これを防ぐ方法はありません...またはそれですか? あります。
メソッドの本質
このメソッドの本質は、リンカに標準の代わりにmalloc / free / new / deleteの実装を使用させることです。 しかし、それを行う方法は? この問題を最初に調査し始めたとき、私の最初の試みはかなり馬鹿げたアイデアでした。つまり、コードに無条件のjmpを配置することにより、ランタイムで本体malloc / freeをメモリにパッチします。 この考えが愚かである理由を説明する必要がありますか? すべてが働いたが、この方法は喜びをもたらさなかったが。 その結果、別の解決策、つまり、リンカーが標準のアロケータが配置されている標準のlibcmtライブラリを使用することを禁止するという解決策を見つけました。 しかし、この方法には重大な欠点もありました。つまり、このライブラリには、カテゴリ的に不可能なスタブを作成するための、非常に有用ではない便利な機能が他にもたくさんあります。
次に、標準ライブラリ(文字通りlibcmt.libファイル)を取得し、そこから余分なライブラリをすべて捨てる可能性を探り始めました。 これが可能であることが判明し、最終的に私はこの方法を使用します。
余談
libcmt.libファイルについて説明していますが、libc.libのすべてが同じであることを理解する必要があります。 これらのライブラリの違いの説明は、この記事の範囲外です。
技術的な詳細
まず、コマンドを実行します:
lib.exe /LIST libcmt.lib
出力は、このライブラリに含まれるobjファイルのリストになります。 Visual Studio 2013のlibcmt.libの場合、このリストは次のようになります。
f:\binaries\Intermediate\vctools\crt_bld\SELF_X86\crt\prebuild\INTEL\mt_lib\chandler4.obj f:\binaries\Intermediate\vctools\crt_bld\SELF_X86\crt\prebuild\INTEL\mt_lib\chandler4gs.obj f:\binaries\Intermediate\vctools\crt_bld\SELF_X86\crt\prebuild\INTEL\mt_lib\chkesp.obj f:\binaries\Intermediate\vctools\crt_bld\SELF_X86\crt\prebuild\INTEL\mt_lib\eh3valid.obj f:\binaries\Intermediate\vctools\crt_bld\SELF_X86\crt\prebuild\INTEL\mt_lib\exsup.obj f:\binaries\Intermediate\vctools\crt_bld\SELF_X86\crt\prebuild\INTEL\mt_lib\exsup2.obj ... ( )
幸いなことに、メモリを操作するためのほとんどすべての関数は個別のobjファイルに配置されているため、実際にはこの方法が可能になります。
つまり ライブラリ本体から不要なobjファイルをすべて削除する必要があります。
/ removeスイッチを指定したlib.exeユーティリティは、必要なことだけを行います。
実装
実際、ソースコードをgithubに投稿しました。
Visual Studio 2013が既にインストールされている場合は、 make_libcmt_nomem.cmdを実行するだけで 、すべての作業が実行され、フルサイズのlibcmtの代わりに接続できるトリミングファイルlibcmt_nomem.libが作成されます。
その作業では、スクリプトはunixユーティリティgrepを使用します。 UnixUtilsがインストールされていない場合は、実行することを強くお勧めします(たとえば、 ここから )。
しかし、それだけではありません。 標準のアロケーターを取り除きました。 しかし問題は、同時にアロケーターと不可分ないくつかの標準機能を削除したことです。 したがって、必要なスタブを作成しました。これはinclude / crtfunc.hファイル(同上、 github )にあります。
申し込み方法
- make_libcmt_nomem.cmdスクリプトを使用して標準ライブラリのトリミングされたバージョンを取得し、リンカーのアクセス可能な場所に配置します。
- 標準のlibcmtライブラリを使用してプロジェクトを無効にします(リンカーの[構成プロパティ]-> [リンカー]-> [入力]のオプションで特定のデフォルトライブラリを無視 "" libcmt ")。
- プロジェクトのc ++ファイルで、ソースから「#include crtfunc.h」を実行します。
- dlmallocをプロジェクトに接続します。
この記事を読んで理解すれば詳細は必要ないので、各項目を詳しく書きません。 唯一の瞬間:C ++(Cではなく)ファイルにcrtfunc.hを含める必要があります。 プロジェクトがCで作成されている場合は、空の.cppファイルをプロジェクトに追加し、crtfunc.hを含める必要があります。 ただし、ファイルの取得を禁止する人はいません。
PS。 実際、dlmalloc'omシングルではありません。 他にも非常に価値のあるアロケーターがあります。 ソースファイルはdlmalloc用に設計されていますが、これは重要ではありません。 crtfunc.hへの最小限の介入は、他のアロケーターを使用して実現できます。
Visual Studio 2015のリリース後、上記のすべての関連性が失われました