2017-10-06 114 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