什么是Empty Base Optimization?
說到C++中的Empty Base Optimization(簡稱ebo)可能大家還是比較陌生,但是C++中每天都在用的std::string
中就用到了ebo。
那么到底什么是ebo呢?其實ebo就是當一個類的對象理想內存占用可以為0的時候,把這個類的對象作為另一個類的成員時,把其內存占用變?yōu)?的一種優(yōu)化方法。說起來可能有點繞,還是用一個例子來說明一下吧,看下面的代碼:
#include
usingnamespacestd;
classBase
{};
intmain()
{
cout<"sizeof(Base)"<sizeof(Base)<"addrobj1"<(void*)&obj1<"addrobj2"<(void*)&obj2<return0;
}
大家能猜到上面的代碼的輸出嗎?sizeof(Base)
會是0嗎?obj1
的地址會和obj2
的一樣嗎?
自己編譯上面的代碼,運行一下,會得到類似下面的輸出(第2、3行會略有不同):
sizeof(Base)1
addrobj10xbfdc9033
addrobj20xbfdc9032
看見了吧?就算Base
不包含任何的成員,編譯器也會讓Base
占1 byte。這是因為如果一個類的內存占用為0,那么連續(xù)的分配對象有可能會有同一個內存地址,這個是不合理的。所以編譯器為了避免這種情況,讓空的類也會占有1 byte的大小。
那么如果我要用Base
作為另一個類的成員變量呢,比如下面這樣:
classTestCls
{
Basem_obj;
intm_num;
};
intmain()
{
cout<"sizeof(TestCls)"<sizeof(TestCls)<return0;
}
知道上面的輸出會是多少嗎?5?在32位的機器上面是8,因為編譯器為了存取的方便,會在m_obj
的后面產生3 byte的padding,以和機器字對齊??傊鸢覆粫?。
但是在內存非常緊張的情況下,還真的會想要讓TestCls
的size是4。有辦法嗎?這里就可以用到今天介紹的ebo
了,看下面的代碼:
classTestCls:publicBase
{
intm_num;
};
intmain()
{
cout<"sizeof(TestCls)"<sizeof(TestCls)<return0;
}
這次能猜到輸出是多少嗎?沒錯,就是我們想要的4!當我們把空的類作為基類的時候,編譯器就會把這個基類的size去掉,做了優(yōu)化, 從而使得整個對象占有真正需要的size。
那么如果這個子類除了基類之外,沒有別的成員呢?如下面:
classTestCls:publicBase
{};
intmain()
{
cout<"sizeof(TestCls)"<sizeof(TestCls)<return0;
}
上面的代碼輸出仍然是1,因為如果這個類本身除了空基類之外沒別的成員, 說明這個類本身也是一個空類,所以最開始說的情況就適用于這里。編譯器就給空類給了1的size。
上面說的就是Empty Base Optimization了。那么現實中哪里使用到了這個技巧呢?除了最開始提到的std::string
之外,Google的cpp-btree也用到了這個技巧。下面我們來看看這兩個現實中的例子。
STL中的string
C++每天都用的string中就用到了ebo。我們來看看string是如何定義成員的(省略函數定義,以下代碼源自gcc 4.1.2 c++):
template<typename_CharT,typename_Traits,typename_Alloc>
classbasic_string
{
public:
mutable_Alloc_hider_M_dataplus;
};
注意string
實際上是模板類basic_string
的一個特化類。而basic_string
只包含了一個成員_M_dataplus
, 其類型為_Alloc_hider
。
我們來看看_Alloc_hider
是怎么定義:
template<typename_CharT,typename_Traits,typename_Alloc>
classbasic_string
{
private:
struct_Alloc_hider:_Alloc//Useebo
{
_CharT*_M_p;//Theactualdata.
};
};
_Alloc_hider
繼承于模板參數類_Alloc
(并且還是私有繼承),還有一個自己的成員_M_p
。_M_p
是用來存放實際數據的,而_Alloc
呢?熟悉STL的人可能還記得STL里面有一個allocator。這個allocator一般的實現都是沒有任何的數據成員,只有static函數的。所以這個類是一個空類。默認的string就是將這個allocator當作模板參數傳遞到_Alloc
。所以_Alloc
大多數情況下都是空類,而string經常會在程序中用到, 還很經常會大量的使用,比如在容器中,這個時候就需要考慮內存占用了。所以在這里就是用了ebo的優(yōu)化。
可能會有人會問,string
里面實際上只有char*
,但是不是說string
還記錄了size, 還用到了copy on write技術的嗎?那怎么只有一個char*
呢?這個和string
的實現中的內存布局相關,其中Copy on write是g++的stl中實現的策略, 想要了解g++的string的內存布局,可以看看陳碩的這篇文章。
cpp-btree中的ebo
cpp-btree是Google出的一個基于B樹的模板容器類庫。如果有不熟悉B樹的童鞋,可以移步這里看一看這個數據結構的動畫演示。
B樹是一種平衡樹結構,一般常用于數據庫的磁盤文件數據結構(不過一般會用其變體B+樹)。而cpp-btree則是全內存的,和std::map
類似的一種容器實現,其對于大量元素(>100w)的存取效率要高于std::map
的紅黑樹實現,并且還節(jié)省內存。
關于cpp-btree的廣告就賣到這里,我們看看他哪里使用了ebo。在cpp-btree里面提供了btree_set
和btree_map
兩個容器類, 而他們的公共實現都在btree
這個類里面。btree
這個類實現了主要的B樹的功能,而其成員定義如下:
template<typenameParams>
classbtree:publicParams::key_compare{
private:
typedeftypenameParams::allocator_typeallocator_type;
typedeftypenameallocator_type::templaterebind<char>::other
internal_allocator_type;
template<typenameBase,typenameData>
structempty_base_handle:publicBase{
empty_base_handle(constBase&b,constData&d)
:Base(b),
data(d){
}
Datadata;
};
empty_base_handleroot_;
};
可以看見btree
這個類里面只包含了root_
這一個成員,其類型為empty_base_handle
。empty_base_handle
是一個繼承于Base的類,在這里,Base
特化成internal_allocator_type
。從名字可以看出internal_allocator_type
是一個allocator, 而在默認的btree_map
實現中,這個allocator就是std::allocator
。所以一般情況下,Base
也是一個空類。
這里btree
也利用了ebo節(jié)省了內存占用。
一個例外
在編譯器判斷是否做ebo的時候,有這么一個例外,就是雖然繼承于一個空類, 但是子類的第一個非static成員的類型也是這個空類或者是這個類的一個子類。在這種情況下,編譯器是不會做ebo的。
有點繞,我們看看下面的代碼就明白了:
#include
usingnamespacestd;
classBase
{};
classTestCls:publicBase
{
public:
Basem_obj;//<<<<
intm_num;
};
intmain()
{
cout<"sizeof(Base)"<sizeof(Base)<"sizeof(TestCls)"<sizeof(TestCls)<"addrobj"<(void*)&obj<"addrobj.m_obj"<(void*)&(obj.m_obj)<"addrobj.m_num"<(void*)&(obj.m_num)<return0;
}
運行一下上面的代碼,你會看到,TestCls
的size是8,并且obj
的地址和obj.m_obj
的地址并不一樣。這說明了ebo并沒有進行。
-
內存
+關注
關注
8文章
3125瀏覽量
75291 -
C++
+關注
關注
22文章
2119瀏覽量
75354 -
代碼
+關注
關注
30文章
4900瀏覽量
70790
原文標題:Empty Base Optimization
文章出處:【微信號:CPP開發(fā)者,微信公眾號:CPP開發(fā)者】歡迎添加關注!文章轉載請注明出處。
發(fā)布評論請先 登錄
Power Optimization SDK介紹之Static API
Parasitic-Aware Optimization o

Practical Optimization(Algorit

Synthesis And Optimization Of
Agilent Optimization of Wirele
Optimization of the MAX4990 Hi
Optimization of the MAX4990 Hi

Optimization of Extraction Technology and Property Analysis of CORTEX

Optimization for PIC Microcontrollers
基于AN_Clock_Optimization模擬到數字轉換的參考設計

評論