【问题标题】:Can`t find memory leak找不到内存泄漏
【发布时间】:2018-04-07 21:08:26
【问题描述】:

也许这不是一个好问题,但我有点绝望。我有内存泄漏,但我不知道如何克服它。 使用 valgrind 查找:

  • 总堆使用量:3 次分配,2 次释放,73,804 字节分配
  • 仍可访问:72,704 字节,1 个块

但我找不到我在代码中丢失“删除”的位置;也许有人可以帮助我

class TData {
public:
    bool IsEmpty;
    int Key;
    char Value[65];
    TData();
    void Print();
};

class TVector {
private:
    size_t capacity;
public:
    TData *array;
    size_t size;
    TVector();
TVector(const size_t &);
    size_t Size() const;
    size_t Capacity() const;
    void Push_back(const TData &);
    void CountingSort(TVector* vector);
    ~TVector();
};

TData::TData() {
    this->Key = 0;
}


void TData::Print() {
    printf("%d\t%s\n", this->Key, this->Value);
}

TVector::TVector() {
    size = 0;
    capacity = 1;
    array = new TData[capacity];
}

TVector::TVector(const size_t & sizeVector) {
    capacity = sizeVector;
    size = 0;
    array = new TData[sizeVector];
}

void TVector::Push_back(const TData &temp) {
    if (size == capacity) {
        capacity *= 2;
        TData *result = new TData[capacity];
        for (int index = 0; index < size; index++) {
            result[index] = array[index];
        }
        delete[] array;
        this->array = result;
    }
    array[size++] = temp;
}


size_t TVector::Size() const {
    return size;
}

size_t TVector::Capacity() const {
    return capacity;
}

void TVector::CountingSort(TVector* vector) {
    int tmp[RANGE] = { 0 };
    TData *out = new TData[vector->Size()];

    for (int i = 0; i < vector->Size(); i++) {
        tmp[vector->array[i].Key]++;
    }
    for (int i = 1; i < RANGE; i++) {
        tmp[i] += tmp[i - 1];
    }
    for (int i = vector->Size() - 1; i >= 0; i--) {
        out[--tmp[vector->array[i].Key]] = vector->array[i];
    }
    for (int i = 0; i < vector->Size(); ++i) {
        vector->array[i] = out[i];
    }
delete[] out;
}



TVector::~TVector() {
    delete[] array;
}


int main(void) {

    TVector v;
    TData data;


    while (scanf("%d%s", &data.Key, data.Value) == 2) {
        v.Push_back(data);
    }

    if (v.Size() > 1) {
        v.CountingSort(&v);
    }
    for (int i = 0; i < v.Size(); ++i) {
        printf("%d\t%s\n", v.array[i].Key, v.array[i].Value);
    }

    return 0;
}

我在尝试使用带有测试的程序时发现了它。我有时间限制错误,我想可能是内存泄漏。我不知道为什么我以前没有检查过。


添加了delete[] out,但仍有内存泄漏

 HEAP SUMMARY:
==4554==     in use at exit: 72,704 bytes in 1 blocks
==4554==   total heap usage: 3 allocs, 2 frees, 73,804 bytes allocated
==4554== 
==4554== 72,704 bytes in 1 blocks are still reachable in loss record 1 of 1
==4554==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4554==    by 0x4EC3EFF: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==4554==    by 0x40106B9: call_init.part.0 (dl-init.c:72)
==4554==    by 0x40107CA: call_init (dl-init.c:30)
==4554==    by 0x40107CA: _dl_init (dl-init.c:120)
==4554==    by 0x4000C69: ??? (in /lib/x86_64-linux-gnu/ld-2.23.so)
==4554== 
==4554== LEAK SUMMARY:
==4554==    definitely lost: 0 bytes in 0 blocks
==4554==    indirectly lost: 0 bytes in 0 blocks
==4554==      possibly lost: 0 bytes in 0 blocks
==4554==    still reachable: 72,704 bytes in 1 blocks
==4554==         suppressed: 0 bytes in 0 blocks
==4554== 
==4554== For counts of detected and suppressed errors, rerun with: -v
==4554== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

【问题讨论】:

  • 使用调试信息 (-g) 编译您的代码,valgrind 会告诉您数据的确切分配位置。
  • 开始使用std::unique_ptr,不再担心内存泄漏。
  • 这是我的学生项目,我不能在那里使用 std::unique_ptr :(
  • 如果您尝试使用TVector 远程执行任何复杂的操作,您可能会遇到问题,因为您没有实现自己的复制构造函数或复制赋值运算符。见rule of 0/3/5
  • @Jully 然后从重新实现您自己的开始——它不会过于复杂,并且可以防止很多这样的问题。

标签: c++ memory-leaks


【解决方案1】:

我想说你这里有内存泄漏(当你使用'new'语句时,你必须记住在同一个对象上也使用'delete'):

void TVector::Push_back(const TData &temp) {
    if (size == capacity) {
        capacity *= 2;
        TData *result = new TData[capacity]; <--allocation
        for (int index = 0; index < size; index++) {
            result[index] = array[index];
        }
        delete[] array; <-- removal of 'array' it's ok but where you delete 'result' - memory allocated but never freed
        this->array = result;
    }
    array[size++] = temp;
}

如果您不能使用“内存”标头中的智能指针(std::unique_ptr、std::shared_ptr、std::weak_ptr)(自 c++11 标准起) - 您可以创建自己的实现来避免这种情况。

template <typename T>
class smart_ptr
{
public:
    smart_ptr()
    {
        value = new T(0);
    }

    smart_ptr(T p_value)
        :value(new T(p_value))
    {}

    T operator*()
    {
        return *value;
    }

    T* operator->()
    {
        return value;
    }

    ~smart_ptr()
    {
        delete value;
    }
private:
    T *value;
};

当您的代码超出函数范围时使用它,“smart_ptr”类的析构函数将被调用 - 不会导致内存泄漏。然而这个太简单了——我仍然建议使用内存头中的“原始”智能指针。会更安全:)

要检测代码中的此类缺陷,您还可以使用 sanitizers 等工具:https://github.com/google/sanitizers/wiki/AddressSanitizer

【讨论】:

    【解决方案2】:
    1. 使用调试信息构建您的程序(使用 gcc 或 clang 标记 -g)。
    2. 使用 --leak-check=full 运行 valgrind:valgrind --leak-check=full a.out

    您没有内存泄漏,您的输出表明某些内存未释放,但仍然可访问

    ==4554== LEAK SUMMARY:
    ==4554==    definitely lost: 0 bytes in 0 blocks
    ==4554==    indirectly lost: 0 bytes in 0 blocks
    ==4554==      possibly lost: 0 bytes in 0 blocks
    ==4554==    still reachable: 72,704 bytes in 1 blocks
    ==4554==         suppressed: 0 bytes in 0 blocks
    

    这不是你的错,而是 GNU Libc 的问题/功能。您可以通过https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66339获取更多信息

    此内存被分配为 C++ 异常的紧急缓冲区,用于内存不足的情况。你可以在这里找到更多信息:What happens if 'throw' fails to allocate memory for exception object?

    这是导致此警告的代码(参见第 123 行):https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/eh_alloc.cc

    它分配

    EMERGENCY_OBJ_SIZE * EMERGENCY_OBJ_COUNT + EMERGENCY_OBJ_COUNT * sizeof (__cxa_dependent_exception)

    相当于

    64 * 1024 + 64 * 112 = 72704

    这是故意这样做的,因为如果你在终止之前分配了一些内存块并没有真正的伤害,所以一些库(尤其是低级库)这样做,主要是为了解决线程环境中对象生命周期的问题.您也可能会在某些 Boost 库中遇到同样的问题 - 我认为 Boost.System 或 Boost.Filesystem 总是会留下 32 字节的内存块。

    【讨论】:

      【解决方案3】:

      您可以尝试使用智能指针来避免此类问题。 some info here

      【讨论】:

        【解决方案4】:

        我没有看到为此释放内存:

        TData *out = new TData[vector->Size()];
        

        【讨论】:

        • 当我尝试为此释放内存时,我有:3 个分配,4 个释放
        • @Jully 尝试只发布一次。
        • @Jully 在 allocs 和 release 上设置断点并进行调试。使用现代和惯用的 C++,将 out 设为向量,它会自行释放内存。使用智能指针(unique/shared_ptr)。 new/delete 这些天是不行的。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-01
        相关资源
        最近更新 更多