2011-01-06 70 views
3

使用新實例化類時。而不是刪除內存基於對象的重用,我們將獲得什麼樣的好處?C++高效地使用新運算符

什麼是新的進程?上下文切換是否發生?新內存分配,誰在分配? OS?

+7

使用比標準之外的其它分配器,應根據分析結果或者通過設計(如內存池)。除此之外,在大多數情況下,實現自帶的分配器都不會有問題。 – AraK 2011-01-06 08:37:21

+0

的確是個好問題。我有一種情況,在分析後,我切換到了許多小而恆定大小的對象的池分配器。我認爲一個上下文切換隻發生在一次分配多個頁面(在Linux上使用mmap),這些頁面在分配器的內部被重用。現在,如果事先知道您分配的對象都具有相同的大小,則會有不同的分配策略。標準庫分配器針對一般情況進行了調整,而不是特定的情況。我聽說有些分配器爲小型,中型和大型對象維護幾個內存池。 – 2011-01-06 09:33:54

回答

5

你已經問了幾個問題在這裏...

不用刪除,我們將獲得基於對象的重用什麼樣的好處記憶的?

這完全取決於您的應用程序。即使假設我知道應用程序是什麼,您也沒有說明另一個細節 - 重用的策略是什麼?但即使知道,一般很難預測或回答。嘗試一些東西並測量它們。

作爲一個經驗法則,我喜歡以儘量減少最爲無償分配。不過,這大多是不成熟的優化。它只會對數千次呼叫產生影響。

什麼是新的進程?

完全依賴執行。但是分配器使用的一般策略是有一個空閒列表,也就是在這個過程中被釋放的塊列表。當空閒列表爲空或連續空閒空間不足時,它必須向內核請求內存,它只能以恆定頁面大小的塊發出。 (在x86上是4096)。分配器還必須決定何時切割,填充或合併塊。多線程也會對分配器施加壓力,因爲它們必須同步它們的空閒列表。

一般來說這是一個非常昂貴的操作。也許與其他你所做的不相關。但它並不便宜。

是否發生上下文切換?
完全可能。它也可能不會。任何時候你的操作系統都可以自由地進行上下文切換,所以當你得到一箇中斷或系統調用時,呃...這可能發生在很多時候;我沒有看到這與你的分配器之間有任何特殊的關係。

分配了新的內存,誰在進行分配? OS?
它可能來自一個空閒列表,在這種情況下不涉及系統調用,因此沒有OS的幫助。但是,如果空閒列表無法滿足請求,它可能來自操作系統。此外,即使它來自空閒列表,您的內核可能已經分頁出了這些數據,因此您可能會在訪問時遇到頁面錯誤,並且內核的分配器將會啓動。所以我想它會是一個混雜的包。當然,你可以有一個符合實現,做各種瘋狂的事情。

2
  • new爲堆上的類分配內存,並調用構造函數。
  • 上下文切換不必發生。
  • C++運行時使用它認爲合適的任何機制在其freestore上分配內存。

通常,C++運行時使用操作系統內存管理函數分配大塊內存,然後使用自己的堆實現細分這些內存塊。微軟的C++運行時大多使用在用戶模式下實現的Win32堆函數,並分配使用虛擬內存apis分配的操作系統內存。因此,直到並且除非它需要虛擬內存的當前分配並且需要去操作系統分配更多的內容,否則沒有上下文切換。

分配內存時存在一個堆遍歷可能會花費多長時間找到一個空閒塊沒有上限有一個理論問題。實際上,堆分配通常很快。

隨着線程應用程序的例外。因爲大多數C++運行時在多個線程之間共享一個堆,所以需要對堆進行序列化。這可能會嚴重降低某些類應用程序的性能,這些應用程序依賴於多個線程可以新建和刪除多個對象。

+0

glibc有一個分配器,它在多線程應用程序中不會降級。 – 2011-01-06 10:57:43

1

如果newdelete地址標記爲已佔據未分配。這些實現不會一直與內核進行通信。更大的內存卡盤被保留,並分成更小的卡盤在您的應用程序中的用戶空間。

因爲newdelete重入(或線程安全取決於實施)可能會發生上下文切換,但您的實現是線程安全的,而無論如何使用默認newdelete

在C++中,您可以覆蓋newdelete運算符,例如,把你的內存管理:

#include <cstdlib> //declarations of malloc and free 
#include <new> 
#include <iostream> 
using namespace std; 

class C { 
public: 
    C(); 
    void* operator new (size_t size); //implicitly declared as a static member function 
    void operator delete (void *p); //implicitly declared as a static member function 
}; 

void* C::operator new (size_t size) throw (const char *){ 
    void * p = malloc(size); 
    if (p == 0) throw "allocation failure"; //instead of std::bad_alloc 
    return p; 
} 

void C::operator delete (void *p){ 
    C* pc = static_cast<C*>(p); 
    free(p); 
} 

int main() { 
    C *p = new C; // calls C::new 
    delete p; // calls C::delete 
}