小物件優化
小物件優化是一種在低階資料結構中使用的技術,例如 std::string
(有時稱為短/小字串優化)。這意味著使用堆疊空間作為緩衝區而不是一些已分配的記憶體,以防內容小到足以容納在保留空間內。
通過新增額外的記憶體開銷和額外的計算,它會嘗試防止昂貴的堆分配。這種技術的好處取決於使用情況,如果使用不當甚至會損害效能。
例
使用此優化實現字串的一種非常天真的方法如下:
#include <cstring>
class string final
{
constexpr static auto SMALL_BUFFER_SIZE = 16;
bool _isAllocated{false}; ///< Remember if we allocated memory
char *_buffer{nullptr}; ///< Pointer to the buffer we are using
char _smallBuffer[SMALL_BUFFER_SIZE]= {'\0'}; ///< Stack space used for SMALL OBJECT OPTIMIZATION
public:
~string()
{
if (_isAllocated)
delete [] _buffer;
}
explicit string(const char *cStyleString)
{
auto stringSize = std::strlen(cStyleString);
_isAllocated = (stringSize > SMALL_BUFFER_SIZE);
if (_isAllocated)
_buffer = new char[stringSize];
else
_buffer = &_smallBuffer[0];
std::strcpy(_buffer, &cStyleString[0]);
}
string(string &&rhs)
: _isAllocated(rhs._isAllocated)
, _buffer(rhs._buffer)
, _smallBuffer(rhs._smallBuffer) //< Not needed if allocated
{
if (_isAllocated)
{
// Prevent double deletion of the memory
rhs._buffer = nullptr;
}
else
{
// Copy over data
std::strcpy(_smallBuffer, rhs._smallBuffer);
_buffer = &_smallBuffer[0];
}
}
// Other methods, including other constructors, copy constructor,
// assignment operators have been omitted for readability
};
正如你在上面的程式碼中所看到的,為了防止某些 new
和 delete
操作,新增了一些額外的複雜性。除此之外,該類具有更大的記憶體佔用,除非在幾種情況下可能不會使用。
通常嘗試使用位操作在指標 _buffer
內編碼 bool 值 _isAllocated
以減小單個例項的大小(intel 64 位:可以將大小減小 8 個位元組)。優化只有在知道平臺的對齊規則時才可能。
什麼時候用?
由於此優化會增加許多複雜性,因此不建議在每個類上使用此優化。在常用的低階資料結構中經常會遇到它。在常見的 C++ 11 standard library
實現中,可以在 std::basic_string<>
和 std::function<>
中找到用法。
由於此優化僅在儲存的資料小於緩衝區時阻止記憶體分配,因此只有在類通常與小資料一起使用時才會帶來好處。
這種優化的最後一個缺點是移動緩衝區需要額外的努力,使得移動操作比不使用緩衝區時更昂貴。當緩衝區包含非 POD 型別時尤其如此。