утечка памяти в c ++ при использовании std :: string в массиве разделяемой памяти - PullRequest
8 голосов
/ 17 мая 2011

У меня есть этот класс

class LayoutEntry
{
  unsigned int id_;
  string name_;  
  bool isInput_;
};

Конструктор копирования выглядит так:

LayoutEntry(const LayoutEntry &other)
        : id_(other.id_),
        name_(other.name_), 
        isInput_(other.isInput_)
    {
    }

Объекты этого класса размещаются внутри карты внутри другого класса

class DataLayoutDescription 
{
    unsigned int sz_;
    set<LayoutEntry, SortByOffset> impl;

    // HERE!!!
    map<unsigned int, LayoutEntry> mapById;

Конструктор копирования этого класса выглядит следующим образом:

DataLayoutDescription::DataLayoutDescription(const DataLayoutDescription &other)
    :sz_(other.sz_), impl(other.impl), mapById(other.mapById)
{   
}

Теперь вопрос:

  • Я получаю утечку памяти для каждого LayoutEntry при запуске как напечатано
  • Если я удаляю mapById(other.mapById) в конструкторе копирования DataLayoutDescription, то нет утечки
  • Если убрать name_(other.name_), Утечки памяти также исчезли

Почему?

EDIT

Для тестирования я использую BOOST :: UnitTest, в конце я получаю дамп утечки памяти

C:\wc\05_EAPGit\Debug>EapLibTest.exe --run-test=SharedVectorTest
Running 7 test cases...

*** No errors detected
Detected memory leaks!
Dumping objects ->
{1378} normal block at 0x005815C0, 16 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
{1377} normal block at 0x00581580, 16 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
{1376} normal block at 0x00581540, 16 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.

Возможная причина? Я сохраняю DataLayoutDescription в области общей памяти, используя этот метод

void DataLayoutDescription::Save(LayoutEntry *les, unsigned int maxEntries) const
{
    int n = std::max(impl.size(), maxEntries);
    int i = 0;
    for (DataLayoutDescription::iterator it = begin(); it != end(); ++it)
    {
        les[i] = *it;  // Source of memory leak here???
        ++i;
    }
}

Я разыменовываю итератор и сохраняю его копию в массиве, который находится в области общей памяти. Что-то не так? Общая память удаляется при выходе.

Furhter Trackdown Класс LayoutEntry размещается в массиве в общей области памяти и содержит строку. Причина утечки памяти в том, что размер строки изменяется. Таким образом, он выделяет больше памяти в куче. Теперь я предполагаю, что эта память не будет освобождена, поскольку исходная память находится в общей памяти. Может ли это быть причиной? Затем я попытаюсь удалить строку и заменить ее массивом символов фиксированной длины.

... через несколько минут

Это было так. После замены строки фиксированным массивом char утечка памяти исчезла. Надеюсь, это кому-нибудь поможет.

Ответы [ 4 ]

4 голосов
/ 17 мая 2011
3 голосов
/ 18 мая 2011

Причиной утечки стал класс LayoutEntry, в котором хранится строка. Базовый объект (до модификации) был помещен в массив в области общей памяти. После изменения строки была выполнена операция изменения размера, эта память была потеряна. После замены строки на массив символов (фиксированной длины) утечка памяти прошла. Я счастлив сейчас, но спрашиваю себя, что класс string делает что-то не так, или есть способ поместить пользовательский распределитель в std :: string? Мне это не понадобится, потому что я пойду с массивом char, но мне просто любопытно, сработает ли что-то подобное, и если я прав с этими предположениями?

Это модифицированный класс

class LayoutEntry
{
  unsigned int id_;
  char name_[128];  
  bool isInput_;
};

Спасибо всем за помощь! Советы по устранению утечки памяти мне очень помогли.

3 голосов
/ 17 мая 2011

Предполагая, что когда вы говорите, что у вас есть утечка памяти, вы имеете в виду какую-то проверку, такую ​​как Purify или valgrind, которая говорит вам об этом, наиболее вероятный сценарий состоит в том, что вы как-то пропускаете LayoutEntry объекты, а НЕ string объекты напрямую. Однажды меня это укусило, и я запутался, потому что мой собственный объект протекал, но утечка была помечена (valgrind) до std::string, что затрудняло поиск.

С другой стороны, это может быть просто обнаружение роста. Вы пытались сделать clear на своей карте до выхода?

1 голос
/ 17 мая 2011

Если у вас есть непротиворечивые номера распределения в утечках, вы можете установить распределитель памяти отладки для прерывания в этом конкретном распределении, используя _CrtSetBreakAlloc.

http://msdn.microsoft.com/en-us/library/4wth1ha5.aspx

Например, добавление _CrtSetBreakAlloc(1378) к вашему коду приведет к прерыванию отладки при выделении номера блока 1378. Затем вы можете использовать отладчик, чтобы следовать коду обратно вызывающей стороне.

...