C++永久對象存儲 (Persistent Object Storage for C++)

C++永久對象存儲 Persistent Object Storage for C++

簡介 描述對象類型 從存儲器中分配和釋放對象 永久對象協議 存儲器構造函數 打開存儲器 POST++ 的安裝 POST++ 類庫 POST++一起使用 STL 替換標準分配子 如何使用 POST++ S調試 POST++ 應用的細節 關於 POST++ 更多的一些信息 簡介

POST++ 提供了對應用對象的簡單有效的存儲. POST++ 基於內存文件鏡像機制和頁面鏡像處理。POST++ 消除了對永久對象訪問的開銷. 此外 POST++ 支持多存儲,虛函數, 數據更新原子操作, 高效的內存分配和爲指定釋放內存方式下可選的垃圾收集器. POST++ 同樣可以很好的工作在多繼續和包含指針的對象上。

 

 

描述對象類型

POST++ 存儲治理需要一些信息以使永久對象類型支持垃圾收集器,裝載時引用重定位和初始化虛表內函數指針。但不幸的是C++語言沒有提供運行時從類中或許這些信息的機制。爲了避免使用一些非凡的工具(預處理器)或“髒哄騙”途徑(從調試信息中獲取類信息),這些信息必須由程序員來指明。這些稱爲類註冊器的東西可以簡單的通過POST++提供的一些宏來實現。

 

POST++ 在從存儲器重載入對象時調用缺省構造函數來初始化對象。爲了使對象句柄能夠存儲,程序員必須在類定義中包含宏 CLASSINFO(NAME, FIELD_LIST) . NAME 指明對象的名字。 FIELD_LIST 描述類的的引用字段。在頭文件 classinfo.h 定義了三個宏用於描述字段:

REF(x) 描述一個字段. REFS(x) 描述一個一維固定數組字段。. (例如:定長數組). VREFS(x) 描述可變一維數組字段。可變數組只能是類的最後一個成員。當你定義類的時候,你可以指定一個僅包含一個元素的數組。具體對象實例中的元素個數可以在生成時指定。

這些宏列表必須用空格分開: REF(a) REF(b) REFS(c). CLASSINFO 定義了缺省構造函數 (沒有參數的構造函數) 和類描述符. 類描述符是類的一個靜態成員名爲 self_class. 這樣類 foo 的描述符可以通過 foo::self_class 訪問. 基類和成員的缺省構造函數會被編譯器自動調用,你不必擔心需要明確調用他們。但是對於序列化的類中的結構成員不要忘記在結構定義中使用 CLASSINFO 宏。然後通過存儲器治理註冊該類使其可被訪問。這個過程由宏 REGISTER(NAME) 完成。類名將和對象一起放在存儲器中。在打開存儲器的時候類在存儲和應用程序之間被鏡像。存儲器中的類名和程序中的類名進行比較。假如有類沒有被程序定義或應用程序和存儲器中的類有不同的大小,程序斷言將失敗。

 

下面的例子闡述了這些規則:

 

strUCt branch { object* obj; int key; CLASSINFO(branch, REF(obj));};class foo : public object { PRotected: foo* next; foo* prev; object* arr[10]; branch branches[8]; int x; int y; object* childs[1]; public: CLASSINFO(foo, REF(next) REF(prev) REFS(arr) VREFS(linked)); foo(int x, int y);};REGISTER(1, foo);main() { storage my_storage("foo.odb"); if (my_storage.open()) { my_root_class* root = (my_root_class*)my_storage.get_root_object(); if (root == NULL) { root = new_in(my_storage, my_root)("some parameters for root"); } ... int n_childs = ...; size_t varying_size = (n_childs-1)*sizeof(object*); // We should suBTract 1 from n_childs, because one element is already // present in fixed part of class. foo* fp = new (foo:self_class, my_storage, varying_size) foo(x, y); ... my_storage.close(); } }

 

 

從存儲器中分配和釋放對象

POST++ 爲了治理存儲內存提供了非凡的內存分配子. 這個分配子使用兩種不同的方法: 針對分配小對象和大對象。所有的存儲內存被劃分爲頁面(頁面的大小和操作系統的頁面大小無關,目前版本的 POST++ 中採用了 512 字節). 小對象是這樣一些對象,他們的大小小於或等於256字節(頁面大小/2. 這些對象被分配成固定大小的塊鏈接起來。每一個 鏈包含相同大小的塊。分配對象的大小以8個字節爲單位。

爲每個對象分配的包含這些塊大小爲256的的鏈的數量最好不要大於14(不同的均衡頁面數). 在每個對象之前 POST++ 分配一個對象頭,包含有對象標識和對象大小。考慮到頭部剛好8個字節,並且在C++中對象的大小總大於0,大小爲8的塊鏈可以捨棄。分配和釋放小對象通常情況下是非常快的: 只需要從L1隊列中進行一次插入/刪除操作. 假如鏈爲空並且我們試圖分配新的對象,新頁被分配用來存儲像目前大小的對象(頁被劃分成塊添加到鏈表中)。大對象(大於256字節)所需要的空間從空閒頁隊列中分配。大對象的大小和頁邊界對齊。POST++ 使用第一次餵給隨機定位算法維護空閒頁隊列(所有頁的空閒段按照地址排列並用一個非凡的指針跟隨隊列的當前位置)。存儲治理的實現見文件 storage.cxx

 

使用顯式還是隱含的內存釋放取決於程序員。顯式內存釋放要快(非凡是對小對象而言)但是隱含內存釋放(垃圾收集)更加可靠。在 POST++ 中使用標誌和清除垃圾收集機制。在存儲中存在一個非凡的對象:根對象。垃圾收集器首先標誌所有的對象可被根對象訪問(也就是可以從根對象到達,和通過引用遍歷)。這樣在第一次GC階段所有未被標誌的對象被釋放。垃圾收集器可以在對象從文件載入的時候生成(假如你傳遞 do_garbage_collection 屬性給 storage::open() 方法)。也可以在程序運行期間調用 storage::do_mark_and_sweep() 方法調用垃圾收集器。但是請務必確定沒有被程序變量指向的對象不可從根對象訪問(這些對象將被GC釋放)。下文詳細請看http://wenku.it168.com/d_000076933.shtml

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章