Мое программное обеспечение все еще использует память после большого количества выделений - PullRequest
0 голосов
/ 16 июля 2011

Я написал небольшой класс очереди на C ++, на Windows.

Просто чтобы проверить, я выделяю 1,0000,000 int с и читаю их обратно.

Очередь работает правильно и очень быстро, но проблема в том, что после полного освобождения диспетчер задач сообщает об использовании некоторой памяти. Например, я все еще получаю 2 МБ памяти, хотя все эти целые числа приводят к + 400 МБ памяти.

Я думал, что это из-за того, что операционная система не выполняет какой-либо GC или что-то еще, но теперь я обнаружил, что это значение (2 МБ) становится 13 МБ, когда я выделяю 100 000 000 целых чисел (в 10 раз больше предыдущего числа). Я не могу найти утечку.

Вот код; как видите, я освобождаю все:

#pragma once

#include <exception>

template <class T>
class colist_item
{

public:

    colist_item() { }
    ~colist_item() { }

    T value;
    colist_item *next;

};

template <class T>
class colist
{

public:

    colist() { this->m_root = NULL; this->m_count = 0; }
    ~colist() { }

    void enqueue(T value);
    T dequeue();
    T *peek();
    int count();

private:
    colist_item<T> *m_root;
    int m_count;

};

template <class T>
void colist<T>::enqueue(T value)
{
    if (this->m_root == NULL) {
        this->m_root = new colist_item<T>();
        this->m_root->value = value;
        this->m_root->next = NULL;
    } else {
        colist_item<T> *tempitem = new colist_item<T>();
        tempitem->value = value;
        tempitem->next = this->m_root;

        this->m_root = tempitem;
    }

    this->m_count++;
}

template <class T>
T colist<T>::dequeue()
{
    if (this->m_root == NULL) {
        throw std::exception();
    } else {
        T retval = this->m_root->value;
        colist_item<T> *next = this->m_root->next;
        delete this->m_root;
        this->m_root = next;

        this->m_count--;
        return retval;

    }
}

template <class T>
T *colist<T>::peek()
{
    if (this->m_root == NULL) {
        return NULL;
    } else {
        T retval = this->m_root->value;
        return &retval;
    }
}

template <class T>
int colist<T>::count()
{
    return this->m_count;
}

Main:

#include <iostream>
#include <limits>
#include "colist.h"
#include <time.h>

const int kNumItems = 100000000;

using namespace std;

void puttest(colist<int> *list)
{
    for(int i = 0; i < kNumItems; i++)
        list->enqueue(i);
}

void readtest(colist<int> *list)
{
    for(int i = 0; i < kNumItems; i++)
        list->dequeue();
}

int main(int argc, char *argv[])
{
    colist<int> list;

    cout << "Testing with : " << kNumItems << " elements" << endl;

    clock_t start = clock();
    puttest(&list);
    clock_t end = clock();

    double ms = ((end - start));
    cout << "puttest: " << ms << endl;

    start = clock();
    readtest(&list);
    end = clock();

    ms = ((end - start));
    cout << "readtest: " << ms << endl;

    cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}

Ответы [ 3 ]

2 голосов
/ 16 июля 2011

Запустите http://valgrind.org/, чтобы убедиться в отсутствии утечек памяти.

как я могу сказать операционной системе, что я выполнил распределение, и она может освободить неподдерживаемую память?

Поскольку вы будете запрашивать больше памяти, библиотека С ++ будет повторно использовать то, что было предоставлено ОС. Так что, как правило, это не проблема.

Иногда из-за фрагментации памяти некоторые куски памяти действительно трудно восстановить. В этом случае вы можете использовать Arena Allocator.

2 голосов
/ 16 июля 2011

ОК, пара ошибок.

Нет деструктора.

У вас нет утечки памяти, поскольку вы удаляете все предметы. Но если вы не удалите их все вручную, тогда ваш класс утечет, когда он выйдет из области видимости. Добавьте деструктор, который просто удаляет все элементы в списке.

Исключение не является безопасным для исключения:

    T retval = this->m_root->value;
    colist_item<T> *next = this->m_root->next;
    delete this->m_root;   // If T is badly designed it could potentially throw an exception.
    this->m_root = next;   // Now you have m_root pointing at a bad object. The idea is to
                           // make sure an exception can not damage your internal structure
                           // of your object. Thus remove it from the chain before you call
                           // delete.

   // Like this
   T               retval    = m_root.value;
   colist_item<T>* oldhead   = m_root;
   m_root                    = oldhead->next;

   // Internal structure updated.
   // Safe to do dangerous tasks.
   delete oldhead;

Использовать список инициализаторов при построении

colist() { this->m_root = NULL; this->m_count = 0; }

// should be

colist():  m_root(NULL), m_count(0) {}

Вам не нужно использовать this везде.

Я знаю, что это поощряется в Java, но в C ++ это обычно не рекомендуется, но признается как стиль. Лично я считаю его беспорядочным использование.

0 голосов
/ 16 июля 2011

Как уже упоминалось в комментариях, вы не должны полагаться на диспетчер задач для анализа использования памяти вашей программой. В этом вопросе перечислены несколько инструментов для Windows, которые подходят для обнаружения утечки памяти.

...