ちょっとマニアック その2『mallocのアライメント』

データを動的に扱うためにmallocというものを使う人も
結構多いのではないのでしょうか?

しかしそのmallocの特性上気を使わないといけない場面が有ります。


そもそもmallocでchar型のデータを確保した時って
実際ヒープにはどのくらいの領域を取られるか知っていますか?

正解は8バイトです。

char型は1バイトだろ!!!
っていう人が出てくるかと思いますが、そこがmalllocの特性上に関わるお話

mallocはどのデータ型にも対応するため戻り値がvoid*なのはご存じですよね?
故に32ビットマシンのdoubleにも対応させなくてはいけません。そのため、
取得される領域は8バイトからとなるわけです。

windowsではさほど問題がない(?)のかもしれませんが、重要なのは
メモリを跨いで取得を行わないという事です。←ちょっと言葉が悪いかも
通常メモリとCPUは4バイトのデータバスで転送が行われます。

例をあげて判り易くご説明しましょう。

1.2000番地から4バイト確保
2.2004番地から2バイト確保
3.2006番地から4バイト確保

この時1のデータ転送はデータバス1回、2も1回
しかし3の場合2回の転送が行われる事になります。
データの転送は大変時間がかかるもの、
プログラマならば余計な処理を少しでも減らしたいものですよね??


その問題を解決するためにアライメントというのは大変重要なものだと
言う事がわかると思います。


実際にアライメントしてからのメモリ確保の方法は
_aligned_mallocというものを使えば簡単に出来ます。
しかし今回はそれを使わずmallocだけを使ってアライメントさせます。
何故_alined_mallocを使わないかと言うと、確保した領域が明示的ではないからです。
実際確保する量は内部で勝手にやってしまうため、
100バイトを128バイトでアライメントして確保してと言っても、実際いくら確保されたか
は知ることが出来ないのです。

ではmallocを使ってのサンプル

#include
#include
#include
int main()
{
static const int ALIGNE_SIZE = 64;

char* str;

str = (char*)malloc((100 + ALIGNE_SIZE -1) / ALIGNE_SIZE * ALIGNE_SIZE);
int size = _msize(str);

std::cout << "malloc時のサイズ:" << size << std::endl;


free(str);
}
出力:
malloc時のサイズ:128

今回は100バイト確保して、64バイトでアライメントをしています。
ちなみにアライメント後に確保された領域のサイズを知るには
_msize(確保したポインタ) これで確保されたサイズを知ることが出来ます。
直接sizeof(str)とかやっても4バイトしか出てきませんよ?

ここで注意!
メモリ確保は最初に言いましたが、8バイト単位で行われます。なので
10バイトとかでアライメントしても無意味です。


こんな感じで終わります