2017-10-06 1 views
0

메모리 누수가있는 오픈 소스 라이브러리에서 작업 중입니다. 라이브러리는 boost :: asio 주변에 구축 된 데이터 스트리밍 서비스입니다. 서버 측은 heap 메모리 관리 시스템을 사용하여 tcp 연결을 통해 밀어 넣기를 기다리는 동안 samples의 유한 번호를 보유하는 메모리를 제공합니다. 서버가 처음 구성 될 때 모든 이전 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_psample 클래스에 템플릿 단지 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; 
} 

코드를 단계별로 살펴보면 삭제 연산자가 샘플 포인터에서 호출되지 않는다는 것을 알 수 있습니다. 내가 작업하고있는 라이브러리 (다시 쓰지는 않았으므로 여전히 그 방법을 배우고있는 라이브러리)가 intrusive_ptr 유형을 잘못 사용하고있는 것 같습니다.

+0

스마트 포인터 유형을 표시하지 않았습니다. –

+0

의심되는 것으로 의심됩니다. 컴파일 할 수있는 MCVE를 게시 할 수 있습니까? –

+0

@RichardHodges가 월요일에 올 것입니다. – dmedine

답변

2

new[]으로 메모리를 할당하므로 delete[] (char*)으로 할당을 해제해야합니다. 스마트 포인터는 기본적으로 delete을 호출하기 때문에 (sample의 소멸자를 수동으로 호출 한 후에) delete[]을 호출하는 사용자 지정 deleter를 제공해야합니다. 다음은 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

"샘플"이 너무 많이 정렬되지 않는다고 가정하면 new 연산자가 new 연산자 *를 호출하여 적절하게 정렬 된 저장 공간을 반환합니다. 왜 그렇게 생각하지 않습니까? –

+0

@MassimilianoJanes 사실. 내 대답에서 그 부분을 제거했습니다. –

+0

이 코드를 작성하지 않았으므로 수정하려고합니다. 왜 원래 저자가 이런 식으로했는지 나는 잘 모르겠습니다. – dmedine

관련 문제