メモリ割り当てしたい(G4Allocator<T>
)
1// 書式: G4ThreadLocal G4Allocator<T>* allocator;
2// 例: SensorHit型のアロケーター
3
4// include/SensorHit.hh で宣言する
5extern G4ThreadLocal G4Allocator<SensorHit>* SensorHitAllocator;
6
7// src/SensorHit.cc で定義する(nullptrで実体化)
8G4ThreadLocal G4Allocator<SensorHit>* SensorHitAllocator = nullptr;
G4Allocator<T>
は、テンプレートクラスであり、
型T
のオブジェクトに特化した高速なメモリ管理ユーティリティです。
このクラスは、高頻度で生成・破棄されるオブジェクトのメモリ確保・解放の効率を最適化する メモリプール型のアロケーター であり、
G4Step
やG4Track
の処理などGeant4内部でも利用されています。
注釈
通常のnew
/ delete
演算子は、頻繁なメモリ確保・解放によりオーバーヘッドが大きくなります。
G4Allocator
では、あらかじめ確保したメモリブロックを使い回すことで、このオーバーヘッドを大幅に軽減します。
ユーザーが明示的に利用する場面は、前述したユーザー定義のヒットクラスです。
対象のユーザー定義クラスで
operator new()
および operator delete()
をオーバーロードし、
その内部でMallocSingle()
/ FreeSingle()
を呼び出す必要があります。
また、マルチスレッド環境では、G4Allocator
をスレッドごとに分離するために、
G4ThreadLocal
を併用します。
メモリを割り当てたい(MallocSingle
)
1SensorHitAllocator->MallocSingle();
MallocSingle
は、G4Allocator
が管理しているメモリプールから、T型(ここではSensorHit
型)オブジェクト1つ分のメモリを割り当てる関数です。
これはC++標準のmalloc
に相当します。
通常は、以下のように
new
演算子(operator new
)をオーバーロードして使います。
1void* SensorHit::operator new(size_t)
2{
3 if(!SensorHitAllocator) {
4 SensorHitAllocator = new G4Allocator<SensorHit>;
5 }
6 return (void *) SensorHitAllocator->MallocSingle();
7};
operator new()
は、コンストラクターが呼ばれるまえに実行される特殊関数です。
ここでSensorHitAllocator
を初期化し、必要なメモリを確保しています。
メモリを解放したい(FreeSingle
)
1SensorHitAllocator->FreeSingle(型名)
FreeSingle
は、MallocSingle
で割り当てたメモリを再びメモリプールに返す関数です。
C++標準のfree
に相当します。
通常は、new
演算子(operator delete
)をオーバーロードして使います。
1void SensorHit::operator delete(void *hit)
2{
3 SensorHitAllocator->FreeSingle((SensorHit*)hit);
4};
operator delete()
演算子は、デストラクターの後に実行される特殊関数です。
前述のnew
演算子で割り当てたメモリを、ここでアロケーターに返却しています。
ヘッダーファイル(include/SensorHit.hh
)
1#include "G4VHit.hh"
2#include "G4Allocator.hh"
3
4class SensorHit : public G4VHit
5{
6 public:
7 void* operator new(size_t);
8 void operator delete(void*);
9 // その他のメンバー変数や関数
10};
11
12//////////////////////////////////////////////////
13// (スレッドローカルな)グローバル変数を宣言
14// 1. スレッドごとにSensorHit型のメモリを管理するためのアロケータ
15// 2. そのメモリ領域を SensorHitAllocator という名前で管理する
16// 3. 実体の定義は .cc ファイルに記述する
17extern G4ThreadLocal G4Allocator<SensorHit>* SensorHitAllocator;
G4Allocator
はユーザー定義のヒットクラスと同じファイルで宣言します。
SensorHitAllocator
のようにグローバルに定義することで、
どこからでもMallocSingl()e
、FreeSingle()
を呼び出して効率的にメモリを管理できます。
1extern G4ThreadLocal G4Allocator<SensorHit>* SensorHitAllocator;
Geant4はマルチスレッド環境がデフォルトになっているため、
各スレッドが独立してアロケーターを保持できるよにG4ThreadLocal
を併用します。
また、C++ではグローバル変数を複数のファイルから参照する場合、
extern
を使って宣言する必要があります。
ソースファイル(src/SensorHit.cc
)
1#include "SensorHit.hh"
2
3G4ThreadLocal G4Allocator<SensorHit>* SensorHitAllocator = nullptr;
4
5void* SensorHit::operator new(size_t)
6{
7 // new演算子でメモリを割り当てるとき
8 // {
9 // SensorHit *hit = new SensorHit();
10 // }
11 // 1. SensorHitAllocatorに割り当てられたメモリのポインターを取得する
12 // 2. 初期化されてない場合は、新しくG4Allocator<TrackerHit>オブジェクトを作成
13 if(!SensorHitAllocator) {
14 SensorHitAllocator = new G4Allocator<SensorHit>;
15 }
16 return (void *) SensorHitAllocator->MallocSingle();
17};
18
19
20
21//////////////////////////////////////////////////
22void SensorHit::operator delete(void *hit)
23{
24 // delete演算子でメモリを解放するとき
25 //
26 // {
27 // SensorHit *hit = new SensorHit();
28 // delete hit
29 // }
30 //
31 // 1. SensorHitAllocatorに割り当てられたメモリのポインターを解放する
32 SensorHitAllocator->FreeSingle((SensorHit*)hit);
33};
G4Allocator
クラスはGeant4に用意されている高速なメモリアロケーターです。
C++のメモリ管理に詳しくないひとは、とりあえず使っておけばよいと思います。
割り当てサイズをしりたい(GetAllocatedSize
)
1// 割り当てられた合計サイズ
2G4int size = SensorHitAllocator->GetAllocatedSize();
3
4// 現在のページのサイズ
5G4int page_size = SensorHitAllocator->GetPageSize();
6
7// 割り当てられたページ数
8G4int n_pages = SensorHitAllocator->GetNoPages();
GetAllocatedSize
で、割り当てられたメモリの合計サイズを確認できます。