Jonathan Furr Ответов: 3

Утечка памяти. Куча растет, но распределений нет


У нас есть программа для windows, написанная на C++, которая имеет утечку памяти. Мы собрали пару свалок,чтобы определить, где утечка. Мой стандартный метод сделать это-использовать WinDbg с помощью ! куча-с на двух свалках выясните, какая куча растет, а потом используйте !куча - стат-ч
Проблема в том, что, хотя я вижу, как растет конкретная куча, ни одно из распределений не растет, когда я бегу !куча-стат-ч. Исторически сложилось так, что эта методология помогла мне выяснить, где протекает моя память, но теперь, похоже, она меня подвела.Куда мне теперь идти?

Что я уже пробовал:

Вот вывод файла дампа из первого дампа:
0:000> !heap -s


************************************************************************************************************************
                                              NT HEAP STATS BELOW
************************************************************************************************************************
LFH Key                   : 0x7230554a
Termination on corruption : DISABLED
  Heap     Flags   Reserv  Commit  Virt   Free  List   UCR  Virt  Lock  Fast 
                    (k)     (k)    (k)     (k) length      blocks cont. heap 
-----------------------------------------------------------------------------
005b0000 00000002    8284   5896   8176    137   148     5    6      b   LFH
00830000 00001002    1188    204   1080     27     8     2    0      0   LFH
02bd0000 00001002    1188    128   1080     24     6     2    0      0   LFH
02b90000 00041002      60      4     60      0     1     1    0      0      
03100000 00001002    1188    128   1080     22     6     2    0      0   LFH
05cc0000 00001003      60      8     60      6     1     1    0    N/A   
05dc0000 00001003    1080    124   1080     77    24     2    0    N/A   
05f10000 00001003      60      4     60      2     1     1    0    N/A   
05ef0000 00001003      60      4     60      2     1     1    0    N/A   
060b0000 00001003      60      4     60      2     1     1    0    N/A   
062a0000 00001003      60      4     60      2     1     1    0    N/A   
05d60000 00001003      60      4     60      2     1     1    0    N/A   
06080000 00001003      60      4     60      2     1     1    0    N/A   
05e70000 00001003      60      4     60      2     1     1    0    N/A   
064a0000 00001003      60      4     60      2     1     1    0    N/A   
05c90000 00001003      60      4     60      2     1     1    0    N/A   
05c50000 00001003      60      4     60      2     1     1    0    N/A   
-----------------------------------------------------------------------------

Вот вывод второго файла:
0:000> !heap -s


************************************************************************************************************************
                                              NT HEAP STATS BELOW
************************************************************************************************************************
LFH Key                   : 0x7230554a
Termination on corruption : DISABLED
  Heap     Flags   Reserv  Commit  Virt   Free  List   UCR  Virt  Lock  Fast 
                    (k)     (k)    (k)     (k) length      blocks cont. heap 
-----------------------------------------------------------------------------
005b0000 00000002   81224  68308  81116   1676   474     9    6     15   LFH
00830000 00001002    1188    260   1080     34     6     2    0      0   LFH
02bd0000 00001002    1188    148   1080     28     6     2    0      0   LFH
02b90000 00041002      60      4     60      0     1     1    0      0      
03100000 00001002    1188    148   1080     27     6     2    0      0   LFH
05cc0000 00001003      60      8     60      6     1     1    0    N/A   
05dc0000 00001003    1080    124   1080     62    57     2    0    N/A   
05f10000 00001003      60      4     60      2     1     1    0    N/A   
05ef0000 00001003      60      4     60      2     1     1    0    N/A   
060b0000 00001003      60      4     60      2     1     1    0    N/A   
062a0000 00001003      60      4     60      2     1     1    0    N/A   
05d60000 00001003      60      4     60      2     1     1    0    N/A   
06080000 00001003      60      4     60      2     1     1    0    N/A   
05e70000 00001003      60      4     60      2     1     1    0    N/A   
064a0000 00001003      60      4     60      2     1     1    0    N/A   
05c90000 00001003      60      4     60      2     1     1    0    N/A   
05c50000 00001003      60      4     60      2     1     1    0    N/A   
21430000 00001002    1188     80   1080     18     8     2    0      0   LFH
-----------------------------------------------------------------------------


Как вы можете видеть, куча в 005b0000 довольно сильно выросла. Теперь, когда я использую ! куча-stat-h 005b0000 первый дамп возвращает следующее:
0:000> !heap -stat -h 005b0000 
 heap @ 005b0000
group-by: TOTSIZE max-display: 20
    size     #blocks     total     ( %) (percent of total busy bytes)
    27c9 25 - 5c00d  (24.26)
    2680 11 - 28e80  (10.78)
    17b0c 1 - 17b0c  (6.25)
    3bc 35 - c5ec  (3.26)
    c da5 - a3bc  (2.70)
    c4 ca - 9aa8  (2.55)
    a0 e4 - 8e80  (2.35)
    8000 1 - 8000  (2.11)
    30 27f - 77d0  (1.97)
    c80 9 - 7080  (1.85)
    24 2d7 - 663c  (1.68)
    1000 5 - 5000  (1.32)
    4e20 1 - 4e20  (1.29)
    4a20 1 - 4a20  (1.22)
    40 10d - 4340  (1.11)
    1048 4 - 4120  (1.07)
    208 20 - 4100  (1.07)
    4040 1 - 4040  (1.06)
    4000 1 - 4000  (1.05)
    2000 2 - 4000  (1.05)


А это из второго файла дампа:
0:000> !heap -stat -h 005b0000 
 heap @ 005b0000
group-by: TOTSIZE max-display: 20
    size     #blocks     total     ( %) (percent of total busy bytes)
    27c9 25 - 5c00d  (23.73)
    2680 11 - 28e80  (10.55)
    17b0c 1 - 17b0c  (6.11)
    3bc 32 - bab8  (3.01)
    c e09 - a86c  (2.71)
    c4 ca - 9aa8  (2.49)
    a0 e6 - 8fc0  (2.32)
    8000 1 - 8000  (2.06)
    30 283 - 7890  (1.94)
    c80 9 - 7080  (1.81)
    24 2d8 - 6660  (1.65)
    40 153 - 54c0  (1.37)
    1000 5 - 5000  (1.29)
    4e20 1 - 4e20  (1.26)
    4a20 1 - 4a20  (1.19)
    1048 4 - 4120  (1.05)
    4040 1 - 4040  (1.04)
    4000 1 - 4000  (1.03)
    2000 2 - 4000  (1.03)
    208 1f - 3ef8  (1.02)

barneyman

возможно, Вам понадобится более активный подход - что-то вроде VLD https://vld.codeplex.com/ может быть полезно

У вас может не быть утечки, вы можете просто фрагментировать кучу?

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

3 Ответов

Рейтинг:
2

KarstenK

Я бы проверил код на наличие интересных кодовых путей, в которых выделяется память. Комментируйте их или запускайте в циклах.

Я решил некоторые проблемы с помощью этого инструмента для Обнаружение Утечек Памяти.

Иногда выделение памяти выполняется системными вызовами, такими как HeapAlloc, где вы не найдете никаких утечек.

Использование vld или других инструментов-это всегда хорошая идея. На главные из них-это пробная версия доступна. ;-)


Рейтинг:
0

Patrice T

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

Отладчик позволяет вам следить за выполнением строка за строкой, проверять переменные, и вы увидите, что есть точка, в которой он перестает делать то, что вы ожидаете.
Отладчик-Википедия, свободная энциклопедия[^]
Освоение отладки в Visual Studio 2010 - руководство для начинающих[^]

Отладчик здесь для того, чтобы показать вам, что делает ваш код, и ваша задача-сравнить его с тем, что он должен делать.
Когда код не делает того, что ожидается, вы близки к ошибке.

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


Рейтинг:
0

George Jonsson

Хороший старый обзор кода также может помочь, особенно если вы можете заставить кого-то еще взглянуть на ваш код.
Пара свежих глаз иногда может обнаружить за считанные минуты проблемы, которые вы пытались найти в течение нескольких часов.

В этом случае вы можете сосредоточиться только на выделении памяти и освобождении памяти.
Ищите все виды аллоков и убедитесь, что вы освободили память во всех путях кода.
Очень часто можно увидеть, что память не освобождается, если код выполняет вторичный путь или возникает исключение.
Нет ничего неслыханного в том, что malloc вызывается дважды и свободен только один раз, потому что код был написан в спешке или более позднее дополнение было сделано другим человеком.

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