ラベル メモリ管理 の投稿を表示しています。 すべての投稿を表示
ラベル メモリ管理 の投稿を表示しています。 すべての投稿を表示

2012年2月19日日曜日

マークスイープGC

本棚本(表紙的に・・・)の著者の一人の中村成洋氏のミニGC
ミニGCの作り方
githubのソース

を参考にシングルスレッド版(Windows7 32bit)のマークスイープGCを作ってみた。
ルーツ選択部分はBoehmGCを参考にした。
レジスタ、スタック、グローバル変数の動作を慎重に吟味。
正しく動作している!のは当然として、参照が外れた時の動作がイメージ通りでなんか感動。
GC面白いなぁ・・・他のアルゴリズムなんかも実装してみたいところだけどちょっと時間がないや。
それにしても氏のソースは少しバグが多い気がする。

2012年2月10日金曜日

BoehmGC(3)

Windows7 32bit 環境での GC_register_dynamic_libraries() より抜粋。
抜粋というと語弊があるのでルーツ選別部分を出力してみた。

*** SYSINFO ***
oem id                : 0
page size             : 4096 bytes
min app address       : 0x00010000
max app address       : 0xbffeffff
active processor mask : 0xff
number of processors  : 8
processor type        : 0x24a
allocation granularity: 65536 bytes
processor level       : 6
processor revision    : 0x1a05

process id: 5908(current)
No  Addr       Size(bytes)  Pages  AllocBase  状態      アクセス許可          タイプ/モジュール名
===================================================================================================
000 0x00000000       65536     16  0x00000000 フリー    アクセス不可                      
001 0x00010000       65536     16  0x00010000 コミット  読み書き可            マップ      
002 0x00020000       65536     16  0x00020000 コミット  読み書き可            マップ      
003 0x00030000     1003520    245  0x00030000 予約                            プライベート
004 0x00125000        4096      1  0x00030000 コミット  読み書き可(ガード)    プライベート
005 0x00126000       40960     10  0x00030000 コミット  読み書き可            プライベート
006 0x00130000       16384      4  0x00130000 コミット  読み込みのみ可        マップ      
007 0x00134000       49152     12  0x00000000 予約余り  アクセス不可                      
008 0x00140000        4096      1  0x00140000 コミット  読み込みのみ可        マップ      
009 0x00141000       61440     15  0x00000000 予約余り  アクセス不可                      
010 0x00150000        4096      1  0x00150000 コミット  読み書き可            プライベート
011 0x00151000       61440     15  0x00000000 予約余り  アクセス不可                      
012 0x00160000      421888    103  0x00160000 コミット  読み込みのみ可        マップ      
013 0x001c7000       36864      9  0x00000000 予約余り  アクセス不可                      
014 0x001d0000      131072     32  0x00000000 フリー    アクセス不可                      
015 0x001f0000       20480      5  0x001f0000 コミット  読み書き可            プライベート
016 0x001f5000       45056     11  0x001f0000 予約                            プライベート
017 0x00200000      131072     32  0x00000000 フリー    アクセス不可                      
018 0x00220000      262144     64  0x00220000 コミット  読み書き可            プライベート
019 0x00260000      786432    192  0x00220000 予約                            プライベート
020 0x00320000      917504    224  0x00000000 フリー    アクセス不可                      
021 0x00400000        4096      1  0x00400000 コミット  読み込みのみ可        イメージ    
022 0x00401000        4096      1  0x00400000 コミット  実行/読み込みのみ可   イメージ    
023 0x00402000        4096      1  0x00400000 コミット  読み込みのみ可        イメージ    
024 0x00403000        4096      1  0x00400000 コミット  読み書き可            イメージ     ※
025 0x00404000        4096      1  0x00400000 コミット  読み込みのみ可        イメージ    
026 0x00405000       45056     11  0x00000000 予約余り  アクセス不可                      
027 0x00410000     1572864    384  0x00000000 フリー    アクセス不可                      
028 0x00590000       12288      3  0x00590000 コミット  読み書き可            プライベート
029 0x00593000       53248     13  0x00590000 予約                            プライベート
030 0x005a0000  1742536704 425424  0x00000000 フリー    アクセス不可                      
031 0x68370000        4096      1  0x68370000 コミット  読み込みのみ可        イメージ    
032 0x68371000      405504     99  0x68370000 コミット  実行/読み込みのみ可   イメージ    
033 0x683d4000      176128     43  0x68370000 コミット  読み込みのみ可        イメージ    
034 0x683ff000        4096      1  0x68370000 コミット  読み書き可            イメージ     ※
035 0x68400000        4096      1  0x68370000 コミット  書き込み時コピー      イメージ    
036 0x68401000        4096      1  0x68370000 コミット  読み書き可            イメージ     ※
037 0x68402000        4096      1  0x68370000 コミット  書き込み時コピー      イメージ    
038 0x68403000       12288      3  0x68370000 コミット  読み書き可            イメージ     ※
039 0x68406000       20480      5  0x68370000 コミット  読み込みのみ可        イメージ    
040 0x6840b000       20480      5  0x00000000 予約余り  アクセス不可                      
041 0x68410000   221380608  54048  0x00000000 フリー    アクセス不可                      
042 0x75730000        4096      1  0x75730000 コミット  読み込みのみ可        イメージ    
043 0x75731000      274432     67  0x75730000 コミット  実行/読み込みのみ可   イメージ    
044 0x75774000        8192      2  0x75730000 コミット  読み書き可            イメージ     ※
045 0x75776000       16384      4  0x75730000 コミット  読み込みのみ可        イメージ    
046 0x7577a000       24576      6  0x00000000 予約余り  アクセス不可                      
047 0x75780000     5636096   1376  0x00000000 フリー    アクセス不可                      
048 0x75ce0000        4096      1  0x75ce0000 コミット  読み込みのみ可        イメージ    
049 0x75ce1000      806912    197  0x75ce0000 コミット  実行/読み込みのみ可   イメージ    
050 0x75da6000        4096      1  0x75ce0000 コミット  読み書き可            イメージ     ※
051 0x75da7000       53248     13  0x75ce0000 コミット  読み込みのみ可        イメージ    
052 0x75db4000       49152     12  0x00000000 予約余り  アクセス不可                      
053 0x75dc0000    19726336   4816  0x00000000 フリー    アクセス不可                      
054 0x77090000        4096      1  0x77090000 コミット  読み込みのみ可        イメージ    
055 0x77091000      651264    159  0x77090000 コミット  実行/読み込みのみ可   イメージ    
056 0x77130000        4096      1  0x77090000 コミット  読み書き可            イメージ     ※
057 0x77131000        4096      1  0x77090000 コミット  書き込み時コピー      イメージ    
058 0x77132000        8192      2  0x77090000 コミット  読み書き可            イメージ     ※
059 0x77134000       12288      3  0x77090000 コミット  書き込み時コピー      イメージ    
060 0x77137000       20480      5  0x77090000 コミット  読み込みのみ可        イメージ    
061 0x7713c000       16384      4  0x00000000 予約余り  アクセス不可                      
062 0x77140000     2228224    544  0x00000000 フリー    アクセス不可                      
063 0x77360000        4096      1  0x77360000 コミット  読み込みのみ可        イメージ    
064 0x77361000      876544    214  0x77360000 コミット  実行/読み込みのみ可   イメージ    
065 0x77437000        4096      1  0x77360000 コミット  読み書き可            イメージ     ※
066 0x77438000        8192      2  0x77360000 コミット  書き込み時コピー      イメージ    
067 0x7743a000        4096      1  0x77360000 コミット  読み書き可            イメージ     ※
068 0x7743b000        4096      1  0x77360000 コミット  書き込み時コピー      イメージ    
069 0x7743c000        8192      2  0x77360000 コミット  読み書き可            イメージ     ※
070 0x7743e000        8192      2  0x77360000 コミット  書き込み時コピー      イメージ    
071 0x77440000      376832     92  0x77360000 コミット  読み込みのみ可        イメージ    
072 0x7749c000       16384      4  0x00000000 予約余り  アクセス不可                      
073 0x774a0000     1048576    256  0x00000000 フリー    アクセス不可                      
074 0x775a0000        4096      1  0x775a0000 コミット  読み込みのみ可        イメージ    
075 0x775a1000       61440     15  0x00000000 予約余り  アクセス不可                      
076 0x775b0000   135528448  33088  0x00000000 フリー    アクセス不可                      
077 0x7f6f0000       20480      5  0x7f6f0000 コミット  読み込みのみ可        マップ      
078 0x7f6f5000     1028096    251  0x7f6f0000 予約                            マップ      
079 0x7f7f0000     8126464   1984  0x00000000 フリー    アクセス不可                      
080 0x7ffb0000      176128     43  0x7ffb0000 コミット  読み込みのみ可        マップ      
081 0x7ffdb000       20480      5  0x00000000 予約余り  アクセス不可                      
082 0x7ffe0000        4096      1  0x7ffe0000 コミット  読み込みのみ可        プライベート
083 0x7ffe1000       61440     15  0x7ffe0000 予約                            プライベート
084 0x7fff0000       57344     14  0x00000000 フリー    アクセス不可                      
085 0x7fffe000        4096      1  0x7fffe000 コミット  読み書き可            プライベート
086 0x7ffff000        4096      1  0x7ffff000 コミット  読み書き可            プライベート
087 0x80000000  1073676288 262128  0x80000000 予約                            プライベート
0xbfff0000     --- アクセス不許可
---------------------------------------------------------------------------------------------------

※が付いている箇所がルーツ対象。

Stack: 0x0012ff4c No:005
Stack: 0x0012ff50 No:005
Stack: 0x0012ff44 No:005
BSS  : 0x00403378 No:024
Data : 0x00403018 No:024
BSS  : 0x004033a8 No:024
Data : 0x0040301c No:024
Stack: 0x0012ff40 No:005
Heap : 0x001f12a0 No:015

下記の順番で No はマッピングされた番号。
・main 関数の引数 int argc
・main 関数の引数 char* argv[]
・main 関数内の自動変数
・未初期化外部変数
・初期化済外部変数
・未初期化静的変数
・初期化済静的変数
・main 関数内の自動変数
・ヒープ

なるほど!

2012年2月8日水曜日

BoehmGC(2)

GC_push_roots から辿れる部分を追ってみた。
・・・改めてBoehmGCの偉大さを痛感した。
なんというべきか、あらゆるCPUとOSの歴史だなこれは。
windowsのみに着目しても頭痛がしそうだ(汗

テストプログラムを書くにしても、何のcpuか何のOSかスレッドの有無を
限定しないと話が進みそうにもないや。

とりあえずVCでもインストールするか。

2012年2月7日火曜日

BoehmGC

Ubuntu側に落として簡単な動作確認。
参照が途切れるタイミングを見ていたが、当然の如くスタックもグローバル変数もバッチリ。

となると、実装方法は1つ。
念のためソースコードを追ってみるとコンパイルスイッチの嵐。
ざっくり見た感じだとデータセグメントを操作している。
x86の実装部分はまだ少し追ってみないと良く分からない部分があるけども。

2012年2月5日日曜日

メモリとか

とある分厚い本を読了。
海の向こうの技術はやっぱり凄いわ・・・。

直接関係はないがメモリー関連の本が欲しいなと物色したら
省メモリプログラミング―メモリ制限のあるシステムのためのソフトウェアパターン集
というものがあったので購入し読了。
非常によくまとまった良書と感じた。

続けてガベージコレクションに興味が沸く。
というのもGCについては上辺程度のことしか知らない。
Androidの場合だとDalvikさんがよろしくやってくれるので最低限のことしか気にしていなかったが
そもそものコンセプトであるメモリ管理に煩わされなくていいよと言われて、はいそうですかというのも
やっぱり気持ち悪い。
そんなわけで取っ掛かりとして
ガベージコレクションのアルゴリズムと実装
を購入しざっくり読了。
非常に分かりやすい解説でアルゴリズムはすんなりと頭に入った。

ただ、実装すると仮定した場合のルートについては理解が不十分なのでメモ書き。
■ヒープ
 これはアロケータも含めての話となるのでルートとすることは簡単。
■スタック(関数の引数とかローカル変数)
 GC初期化~直前のローカル変数のアドレス間を操作。
■レジスタ
 GC直前にアセンブリかsetjmpでレジスタ取得を行い操作。
 環境依存を考慮すると後者が一般的。

スタックとレジスタについては若干悩んだが、
・GCは不要とされるオブジェクトを破棄する
・GCされることで実行コード(スタックやレジスタ)に影響があっては困る
という点から、スタックやレジスタが有効とされるアドレスを参照しているならば
GCには破棄させないということで操作については納得した。

グローバル変数については気になることが色々あるのでオープンソースな実装を読んでいる。
Rubyの場合はrb_gc_register_addressで内部で保持するリストに登録してる感じのようだ。
C/C++ネイティブなものも知る必要があるのでBoehmGCも併読。

2011年12月27日火曜日

アライメント

主にJavaを触っているのだが、よく考えればメモリー管理はよろしくやってくれるわけで・・・。
アドレスも見れないし見る必要がないコンセプトなのでいいやと思いつつも、何故かC++版を
書いてみたい衝動に駆られ、久しぶりにC/C++コンパイラーを起動した。
すぐに終わるだろうと考えていたが、環境がUbuntu-64bit(Android-Gingerbread以上)なことを
すっかり忘れていたため、予想外に時間が掛かってしまった。
C/C++関連は32bitOSにどっぷりと慣れていたからなぁ・・・。

// アライメントの計算
uintptr_t alignment(uintptr_t rawAddress, size_t align){
    align--;
    return (rawAddress + align) & ~align;
}

void* allocateAligned(size_t size, size_t align){
    // 2の羃乗でない場合はアサート
    assert(((align - 1) & align) == 0);
    // 実際に確保するサイズ(actual_size = request_size + (align - 1) + offset_size)
    size_t actualSize = size + (align - 1) + sizeof(void*);
    // アラインされていないメモリ確保
    void* pRawAddress = malloc(actualSize);
    if(pRawAddress == NULL)
        return NULL;
    // オフセットアドレスに生アドレスを書き込む
    uintptr_t rawAddress = reinterpret_cast<uintptr_t>(pRawAddress);
    uintptr_t alignedAddress = alignment(rawAddress + sizeof(void*), align);
    ptrdiff_t offsetAddress = alignedAddress - sizeof(void*);
    void** ppOffsetAddress = reinterpret_cast<void**>(offsetAddress);
    *ppOffsetAddress = pRawAddress;
    // アラインされたアドレスへのポインタを返す
    return reinterpret_cast<void*>(alignedAddress);
}

void Allocator::freeAligned(void* p){
    assert(p != NULL);
    uintptr_t alignedAddress = reinterpret_cast<uintptr_t>(p);
    uintptr_t offsetAddress = alignedAddress - sizeof(void*);
    void** ppOffsetAddress = reinterpret_cast<void**>(offsetAddress);
    // アラインされていないアドレスへのポインタで解放
    free(*ppOffsetAddress);
}

64bitなのでポインターサイズは8bytes。
32bitなら気にせず unsigend int で済ましても問題がなかったところ。
uintptr_t、ptrdiff_t、size_t が環境によって自動的に変わるため、これを利用すればいい。

※オフセット値を2bytesで保持していたが、アドレスを直接持つように変更