2017-10-06 115 views
0

我正在開發一個內存泄漏的庫。該庫是一個基於boost :: asio構建的數據流服務。服務器端使用堆內存管理系統,該系統提供內存以保存有限數量的samples,同時等待通過tcp連接進行推送。當第一次構建服務器時,將爲所有舊的sample分配一堆內存。從這個堆中,在穿過套接字傳遞一個sample之後,內存將返回到堆中。避免內存泄漏造成的新(新[])

這很好,除非所有預先分配的堆已被佔用。下面是創建一個「樣本」的功能:

sample_p new_sample(double timestamp, bool pushthrough) { 
    sample *result = pop_freelist(); 
    if (!result){ 
     result = new(new char[sample_size_]) sample(fmt_, num_chans_, this); 
    } 
    return sample_p(result); 
} 

sample_p只是模板到sample類typedef定義智能指針。

違規行在中間。當freelist上沒有一塊內存時,我們需要做一些。這會泄漏內存。

我的問題是爲什麼會發生這種情況?由於我將新樣本推送到智能指針中,因此當內存超出範圍時它不應該釋放內存(稍後它會從堆棧中彈出)。我是否需要以某種方式處理內部分配的內存 - 即。內存分配由new char[sample_size_]?如果是的話,我該怎麼做?

編輯: @RichardHodges這裏是一個可編譯的MCVE。這是非常簡單的,但我認爲它捕捉到我在原代碼中遇到的問題。

#include <boost/intrusive_ptr.hpp> 
#include <boost/lockfree/spsc_queue.hpp> 
#include <iostream> 

typedef boost::intrusive_ptr<class sample> sample_p; 
typedef boost::lockfree::spsc_queue<sample_p> buffer; 
class sample { 

public: 
    double data; 
    class factory{ 
    public: 
     friend class sample; 
     sample_p new_sample(int size, double data) { 
      sample* result = new(new char[size]) sample(data); 
      return sample_p(result); 
     } 
    }; 

    sample(double d) { 
     data = d; 
    } 

    void operator delete(void *x) { 
     delete[](char*)x; 
    } 

    /// Increment ref count. 
    friend void intrusive_ptr_add_ref(sample *s) { 

    } 

    /// Decrement ref count and reclaim if unreferenced. 
    friend void intrusive_ptr_release(sample *s) { 

    } 

}; 


void push_sample(buffer &buff, const sample_p &samp) { 

    while (!buff.push(samp)) { 
     sample_p dummy; 
     buff.pop(dummy); 
    } 
} 

int main(void){ 
    buffer buff(1); 
    sample::factory factory_; 
    for (int i = 0; i < 10; i++) 
     push_sample(buff, factory_.new_sample(100,0.0)); 
    std::cout << "press any key to exit" << std::endl; 
    char foo; 
    std::cin >> foo; 

    return 0; 
} 

當我逐句通過代碼時,我注意到我的delete操作符永遠不會被樣本指針調用。我猜想我正在處理的庫(我再也沒有寫過,因此我仍然在學習它的方法)錯誤地使用了intrusive_ptr類型。

+0

你沒有顯示智能指針類型... –

+0

這看起來像是地獄。你能發佈一個編譯的MCVE嗎? –

+0

@RichardHodges星期一來。 – dmedine

回答

2

您正在使用new[]分配內存,因此您需要使用delete[](位於char*)來分配內存。智能指針在默認情況下可能會調用delete,所以您應該提供一個自定義刪除程序,該程序調用delete[](手動調用sample的析構函數之後)。這裏是一個使用std::shared_ptr的例子。

auto s = std::shared_ptr<sample>(
    new (new char[sizeof(sample)]) sample, 
    [](sample* p) { 
    p->~sample(); 
    delete[] reinterpret_cast<char*>(p); 
    } 
); 

可是,爲什麼你正在使用放置new當你的緩衝區只包含一個對象?爲什麼不使用常規的new代替?

auto s = std::shared_ptr<sample>(new sample); 

或甚至更好(與std::shared_ptr),使用工廠功能。

auto s = std::make_shared<sample>(); 
+0

假設「樣本」沒有超過標準,由數組新的表達式*調用的默認操作符將*返回適當對齊的存儲空間,爲什麼你認爲不是? –

+0

@MassimilianoJanes是的。我從我的答案中刪除了這部分內容。 –

+0

我沒有寫這段代碼,我只是想解決它。我不確定原作者爲什麼這樣做。 – dmedine