1. 程式人生 > >作為區域性變數的std::string和標準庫容器一種記憶體優化方法

作為區域性變數的std::string和標準庫容器一種記憶體優化方法

實際專案中,往往看到好多專案把std::string, std::vector作為區域性變數直接使用的情況。 類似下面std::string的用法:

void SomeClass::Fun()
{
        std::string str = "abcd";
        str += "efgh";
}
        
下面是std::vector的類似例子:
void SomeClass::Fun2()
{
        std::vector<int> iv;
        iv.push_back(22);
        
        DoFun2(iv);
}
       

在後臺伺服器出現上面類似的程式碼最好還是優化一下。上面程式碼涉及堆記憶體的申請和釋放,執行頻繁的話,會產生碎片。

一種優化方法是,把std::string作為SomeClass的成員變數:

class SomeClass
{
private:
      std::string m_str;
};

void SomeClass::Fun()
{
        m_str.clear();      // 每次用的時候,清一下
        m_str = "abcd";
        m_str += "efgh";
}

std::string的特點是clear()的時候,只清內容,不釋放記憶體。std::vector也有這類特點,也可用類似的方法。

還有一類容器,比如std::list, std::map, xxx::hash_map等, clear()的時候,同時也會釋放記憶體,這個也好辦,傳一個allocator給他。下面用 std::list舉例,std::string麻煩一點, 得用std::basic_string.

class SomeClass
{
private:
      std::list<int, __gnu_cxx::pool_alloc<int> > m_list;
};

這樣呼叫m_list.clear()的時候,記憶體的釋放從pool_alloc釋放。避免了從堆中分配和釋放了。

上面一種方法如果SomeClass的物件生命週期結束了,allocator中的記憶體還是會釋放。我們可以考慮第二種方法,引入一個全域性性質的allocator,只要型別一樣的區域性容器都可以用。這樣類物件的生命週期結束了,也不會引起記憶體釋放。

YourAllocator<int> g_intAllocator;

void SomeClass::Fun()
{
     std::vector<int, YourAllocator<int> > v(g_intAllocator);
     UseV(v);
}

YourAllocator,Linux上可以用__gnu_cxx::pool_alloc.   其他需要int的區域性容器變數,可以共用這個g_intAllocator。這樣記憶體的申請和分配都在g_intAllocator內部進行,都是O(1),記憶體也很緊湊,保證高效。