#はじめに
初めてC++に触れてから約4年。
恥ずかしながら初めてアライメントを意識したので、覚書としてまとめておきます。
#なぜ意識したか
八分木による空間分割を実装していた時の話です。
静的に分割を行うと常時 *空間数(約240k)クラスサイズB のメモリが必要になりました。
そのためクラスサイズを落とせないか考えるうちに、意識した次第です。
#アライメントとは
記憶装置にデータを書き込む際、書き込むデータの大きさや先頭の位置(アドレス)を、装置の管理単位の整数倍になるように調節すること。例えば、4バイト単位でメインメモリを管理してるコンピュータで、メモリ上に置くデータの先頭アドレスが4の倍数になるように調節する。こうすることで、装置がデータの読み書きを効率良く行うことができるようになり、処理効率の向上が見込める。※1
だそうです。
これを意識しないと、無駄な領域を発生させてしまいます。
#アライメントを意識しないと
class A // 4B
{
A* pA;
};
class B // 8B
{
bool hoge;
bool foo;
B* pB;
};
class C // 12B
{
bool hoge;
c* pC;
bool foo;
};
BとCの内容は同じですが,Cにパディングが挿入され4バイト無駄にしています。※2
これが既述の八分木で起きた場合、約10MBもの無駄が発生してしまいます。
これを抑えるために、アライメントを意識してメンバを並べなければいけません。
#アライメントを意識する上で必要なこと
パディングが挿入されないように並べるためには、データのサイズを知っておく必要があります。
全ての型のサイズを覚えるのは厳しいので、有名所を書いておきます。
64bitCpu:VisualStudio2015:x86環境で実行しています
・組み込み型
型 | サイズ(バイト) |
---|---|
int | 4 |
unsigned int | 4 |
char | 1 |
unsigned char | 1 |
short | 2 |
unsigned short | 2 |
__int64 | 8 |
bool | 1 |
float | 4 |
double | 8 |
・参照
参照のサイズに付いては別の記事で書かれていました。
ポインタのサイズと同等と考えて良さそうです。
・ポインタ
ポインタはx86の場合4バイト、x64の場合8バイトです。
・コンテナ
型 | サイズ(バイト) |
---|---|
list | 12 |
vector | 16 |
deque | 20 |
forward_list | 8 |
map | 12 |
unordered_map | 40 |
unordered_set | 40 |
array | 要素サイズ*要素数 |
デフォルトテンプレート引数を変更しない場合の数値です。
・その他
型 | サイズ(バイト) |
---|---|
string | 28 |
shared_ptr | 8 |
function | 40 |
system_clock | 1 |
thread | 8 |
mutex | 48 |
type_index | 4 |
#まとめ
数バイトですが無駄な領域です。
プロジェクト全体となれば結構な量になるはずです。
細かいことですが、気にかけてみては如何でしょうか?
註釈
※1 知的快楽主義者の備忘録 Wiki様
http://wikiwiki.jp/takemaster/?IT%CD%D1%B8%EC%2F%A5%A2%A5%E9%A5%A4%A5%E1%A5%F3%A5%C8%20%A1%DA%20alignment%20%A1%DB%20%A5%A2%A5%E9%A5%A4%A5%F3%A5%E1%A5%F3%A5%C8
※2 64bitCpu、VisualStudio2015でx86環境で実行しています。
今回のプロジェクトはここで公開しています。