-1

Maybe this is not a good question to post but I am kinda desperate. I have a memory leak, but i don't know how to overcome it. Using valgrind find:

  • total heap usage: 3 allocs, 2 frees, 73,804 bytes allocated
  • still reachable: 72,704 bytes in 1 blocks

but i can`t find where i lost "delete" in code; Maybe someone can help me with

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;
}

I finded it when try use program with tests. I have time limit error and i thought maybe it can be memory leaks. I don't know why i didn't checked it before.


Added delete[] out, but stil have memory leak

 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)
Jully
  • 21
  • 2
  • Compile your code with debug info (`-g`) and valgrind will tell you exactly where the data was allocated. – Jonathon Reinhart Oct 26 '17 at 13:04
  • Start using `std::unique_ptr` and stop worrying about memory leaks. – Quentin Oct 26 '17 at 13:07
  • This is for my student project and i cant use there std::unique_ptr :( – Jully Oct 26 '17 at 13:11
  • 3
    If you try to do anything remotely complicated with `TVector` you are likely to encounter problems because you did not implement your own copy constructor or copy assignment operator. See [rule of 0/3/5](http://en.cppreference.com/w/cpp/language/rule_of_three). – François Andrieux Oct 26 '17 at 13:15
  • @Jully then start by reimplementing your own -- it's not excessively complicated and will prevent a *lot* of such issues. – Quentin Oct 26 '17 at 14:24

4 Answers4

3

I don't see releasing memory for this:

TData *out = new TData[vector->Size()];
Andrey
  • 59,039
  • 12
  • 119
  • 163
  • When i try to release memory for this i have: 3 allocs, 4 frees – Jully Oct 26 '17 at 13:12
  • @Jully try releasing it only once. – eerorika Oct 26 '17 at 13:15
  • @Jully put breakpoints on allocs and releases and debug. Use modern and idiomatic C++, make `out` a vector and it will release memory itself. Use smart pointers (unique/shared_ptr). `new/delete` is no-go these days. – Andrey Oct 26 '17 at 13:33
2
  1. Build your program with debugging information (flag -g with gcc or clang).
  2. Run valgrind with --leak-check=full: valgrind --leak-check=full a.out.

You don't have a memory leak, your outputs says that some memory was not free'd, but is still reachable:

==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

This is not your fault, but an issue/feature with GNU Libc. You can get more information at https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66339

This memory is allocated as an emergency buffer for C++ exceptions for low memory situations. You can find more info here: What happens if 'throw' fails to allocate memory for exception object?

This is the code that causes this warning (see line 123): https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/eh_alloc.cc

It allocates

EMERGENCY_OBJ_SIZE * EMERGENCY_OBJ_COUNT + EMERGENCY_OBJ_COUNT * sizeof (__cxa_dependent_exception)

which is equivalent of

64 * 1024 + 64 * 112 = 72704

This was done on purpose, as it doesn't really hurt if you live some memory chunk allocated before termination, so some libraries (especially low-level ones) do this, mostly to solve their issues with object lifetime in threaded environment. You may encounter the same issue with some Boost libraries too - I think either Boost.System or Boost.Filesystem always leaves 32 byte memory chunk hanging around.

1

You can try using smart pointers to avoid this type of problems. some info here

1

I would say that you have memory leak here (when you are using 'new' statement you have to remember to use 'delete' as well on the same object):

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;
}

If you can't use smart pointers (std::unique_ptr, std::shared_ptr, std::weak_ptr) which are in 'memory' header(since c++11 standard) - you can create your own implementation to avoid this.

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;
};

When you will use it when your code will go out of scope of function destructor of 'smart_ptr' class will be called - will not cause memory leak. However this one is too simple - still I recommend to using 'original' smart pointers from memory header. It will be much safer :)

To detect this kind of defect in your code you can use tools like sanitizers as well: https://github.com/google/sanitizers/wiki/AddressSanitizer

thebarylowi
  • 55
  • 1
  • 1
  • 7