MGL::Memory::Allocator
Contents
MGL::Memory::Allocator#
概要#
MGL::Memory::AllocatorはMGL用のメモリアロケータを実装するためのインターフェースクラスです。このインターフェースを継承したクラスを用いることで、MGLが使用するアロケータを任意のものに変更可能となります。
独自アロケータの実装についてはメモリアロケータの作成(準備中)を参照してください。
宣言#
namespace MGL::Memory
{
class Allocator;
}
メンバ情報#
種類 |
名前 |
内容 |
---|---|---|
純粋仮想関数 |
このアロケータを表す値の取得 |
|
純粋仮想関数 |
初期化処理 |
|
純粋仮想関数 |
初期化状態の取得 |
|
純粋仮想関数 |
メモリの確保 |
|
純粋仮想関数 |
メモリの解放 |
|
純粋仮想関数 |
サイズ情報を取得 |
GetType#
このアロケータを表す値の取得
宣言#
namespace MGL::Memory
{
class Allocator
{
[[nodiscard]] virtual AllocatorType GetType() const noexcept = 0;
};
}
戻り値#
- MGL::Memory::AllocatorType
このアロケータを表す値
説明#
外部からこのアロケータを判別する際に使用する値を取得します。この関数はMGL::Memory::GetAllocatorTypeが使用中のアロケータに対して呼び出しを行います。
この関数の戻り値にはMGL::Memory::MakeAllocatorTypeに任意の文字列を与えて生成した値を返してください。
利用例#
class YourAllocator : public MGL::Memory::Allocator
{
public:
// このアロケータを表す値を生成。
// publicな定数にしておくと判別の際に利用しやすい。
static constexpr auto kAllocatorType = MGL::Memory::MakeAllocatorType("YourAllocatorName");
// このアロケータを表す値を取得
virtual AllocatorType GetType() const noexcept override
{
return kAllocatorType;
}
... // その他の実装
};
関連#
Initialize#
初期化処理
宣言#
namespace MGL::Memory
{
class Allocator
{
virtual bool Initialize() noexcept = 0;
};
}
戻り値#
- bool
成功時に
true
、失敗時にfalse
説明#
アロケータの初期化を行う関数です。
この関数はMGL::Memory::SetAllocatorが呼び出された際に、IsInitializedがfalse
を返す場合に自動で呼び出されます。手動で呼び出したい場合は、この関数を呼び出した後にIsInitializedがtrue
を返すように実装してください。
MGL::Memory::SetAllocatorがこの関数を呼び出してfalse
が返された場合、アロケータの登録は行われません。
利用例#
// 初期化まわりの実装例
class YourAllocator : public MGL::Memory::Allocator
{
public:
// コンストラクタで初期化済みフラグをfalseに設定
constexpr YourAllocator() noexcept
: _isInitialized(false)
{
}
// 初期化処理
virtual bool Initialize() noexcept override
{
... // 初期化処理
_isInitialized = true;
}
// 初期化状態を取得
virtual bool IsInitialized() const noexcept override
{
return _isInitialized;
}
... // その他の実装
private:
bool _isInitialized; // 初期化フラグ
};
呼び出し側の例についてはMGL::Memory::SetAllocatorを参照してください。
関連#
IsInitialized#
初期化状態の取得
宣言#
namespace MGL::Memory
{
class Allocator
{
[[nodiscard]] virtual bool IsInitialized() const noexcept = 0;
};
}
戻り値#
- bool
初期化済みまたは初期化不要の場合は
true
、初期化が必要な場合はfalse
説明#
アロケータの初期化状態を返す関数です。アロケータが初期化済み、または初期化の必要がない場合はtrue
を返してください。
この関数がfalse
を返すアロケータをMGL::Memory::SetAllocatorに指定した場合、内部でInitializeを呼び出して初期化を試みます。初期化に失敗した場合はアロケータの登録は行われません。
利用例#
初期化処理も含めてInitializeを参照してください。
関連#
Allocate#
メモリの確保
宣言#
namespace MGL::Memory
{
class Allocator
{
[[nodiscard]] virtual void *Allocate(size_t size) noexcept = 0;
};
}
引数#
- size_t size
要求サイズ
戻り値#
- void *
確保したバッファの先頭アドレス。失敗時には
nullptr
説明#
このアロケータを用いてメモリの確保を行う際に呼び出される関数です。この関数はMGL::Memory::Allocateによって呼び出されます。
引数で指定されたサイズを満たす利用可能なバッファを準備し、その先頭アドレスを返してください。メモリの確保に失敗した場合はnullptr
を返してください。
この関数は異なる複数のスレッドから同時に呼び出される可能性があるため、マルチスレッドセーフな実装である必要があります。
注釈
MGLはメモリの確保に失敗した場合のプログラムの継続を保証していません。MGL::STL名前空間以下のクラスまたは関数においてはstd::bad_alloc
をスローしますが、それ以外の多くの状況ではstd::terminate()
によってプログラムを異常終了させます。ゲームプログラミングにおいては、メモリの確保に失敗する状況を作らないことを優先してください。
利用例#
アロケータの実装依存につき省略します。呼び出し側の利用例についてはMGL::Memory::Allocateを参照してください。
関連#
Deallocate#
メモリの解放
宣言#
namespace MGL::Memory
{
class Allocator
{
virtual void Deallocate(void *buffer) noexcept = 0;
};
}
引数#
- void *buffer
解放するバッファのアドレス
説明#
このアロケータによって確保されたバッファを解放する際に呼び出される関数です。この関数はMGL::Memory::Deallocateによって呼び出されます。
引数で受けたアドレスをアロケータへと返却する処理を実装してください。
この関数は異なる複数のスレッドから同時に呼び出される可能性があるため、マルチスレッドセーフな実装である必要があります。
注釈
Cのfree()およびC++のdeleteはNULLポインタを受けた際に何も行わない事が規定されていますが、その処理はこの関数の呼び出し元で行われているため、この関数内部でNULLチェックを行う必要はありません。
利用例#
アロケータの実装依存につき省略します。呼び出し側の利用例についてはMGL::Memory::Allocateを参照してください。
関連#
GetSizeInfo#
サイズ情報を取得
宣言#
namespace MGL::Memory
{
class Allocator
{
virtual bool GetSizeInfo(size_t &dest, uint32_t key, uint32_t arg) noexcept = 0;
};
}
引数#
- size_t &dest
取得したサイズ情報の格納先
- uint32_t key
取得するサイズの種類を表すキー
- uint32_t arg
取得の際に使用する引数
戻り値#
- bool
成功時に
true
、失敗時にfalse
説明#
このアロケータのサイズ情報を取得する際に呼び出される関数です。この関数はMGL::Memory::GetSizeInfoによって呼び出されます。
この関数は主にメモリの使用状況をモニタリングする際に利用します。アプリケーション側でモニタリングする必要が無い場合はこの関数の実装は不要ですので、単にfalse
を返すだけで問題ありません。
アロケータがどのようなサイズを扱うかは実装するアルゴリズムに依存するため、MGL側では明確な定義を行っていません。多くの場合、確保可能な最大容量や確保済みの総容量、確保しているバッファの数などがアプリケーション側にとって有用な情報となります。引数のkey
がどの種類の情報を表し、arg
がどのように扱われるかについてはアロケータ側で定義してください。
情報が正しく取得できた場合、dest
にその結果を書き込みtrue
を返してください。key
に対応する情報が存在しない場合など、情報が取得できなかった場合はfalse
を返してください。
利用例#
// 確保済みのサイズ、確保数、確保可能な最大サイズを返す例
class YourAllocator : public MGL::Memory::Allocator
{
public:
// サイズ情報に対応するキーの定義
enum
{
kSizeKey_UsedSize, // 確保済みのサイズを表すキー
kSizeKey_UsedCount, // 確保数を表すキー
kSizeKey_MaxAllocatableSize, // 確保可能な最大サイズを表すキー
};
// サイズ情報を取得
virtual bool GetSizeInfo(size_t &dest, uint32_t key, uint32_t arg) noexcept override
{
// サイズ情報は異なるスレッドによって書き換えられる可能性があるため、
// 取得の際にも同期を取らないと正しい値が得られない場合がある。
std::lock_guard lock(_mutex);
switch (key)
{
// 確保済みのサイズ
case kSizeKey_UsedSize:
dest = _usedSize;
return true;
// 確保数
case kSizeKey_UsedCount:
dest = _usedCount;
return true;
// 確保可能な最大サイズ
case kSizeKey_MaxAllocatableSize:
dest = _maxAllocatableSize;
return true;
default:
break;
}
// 上記に該当しないキーを受けた場合はfalseを返す
return false;
}
... // その他の実装
private:
// 各種サイズ情報
// これらの変数は Allocate() / Deallocate() によって変動するものとする
size_t _usedSize; // 確保済みのサイズ
size_t _usedCount; // 確保数
size_t _maxAllocatableSize; // 確保可能な最大サイズ
// 同期用のmutex
// このmutexは Allocate() / Deallocate() でも使用すると想定
std::mutex _mutex;
};