Почему эта утечка памяти? - PullRequest
       47

Почему эта утечка памяти?

2 голосов
/ 11 августа 2011

У меня есть функция, которая при вызове берет поле struct Pieces* из struct Torrent и инициализирует его согласно информации, содержащейся в массиве символов.

Вот как выглядит вызов функции (metadata.c: 230):

get_pieces(t.pieces, &t.num_pieces, data);

В функции get_pieces() я инициализирую t.pieces, вот так (metadata.c: 65):

pieces = calloc(*num_pieces, sizeof(struct Piece));

Однако, когда я запускаю valgrind, он говорит:

==8701== 76,776 bytes in 1 blocks are definitely lost in loss record 634 of 634
==8701==    at 0x4C28349: calloc (vg_replace_malloc.c:467)
==8701==    by 0x4025A4: get_pieces (metadata.c:65)
==8701==    by 0x402CDB: init_torrent (metadata.c:230)
==8701==    by 0x404018: start_torrent (torrent.c:35)
==8701==    by 0x40232E: main (main.c:17)

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

Полный исходный код доступен по адресу https://github.com/robertseaton/slug.

Ответы [ 3 ]

8 голосов
/ 11 августа 2011

У вас есть

void get_pieces (struct Piece* pieces, uint64_t* num_pieces, char* data)
{
    /* ... */
    pieces = malloc(sizeof(struct Piece) * *num_pieces);
}

После выполнения функции объект, переданный вызывающей стороной в качестве первого аргумента, не изменяется, поэтому результат malloc теряется . Поэтому я не вижу, как вы можете освободить pieces.

EDIT

Как пользователь user786653 замечает в комментариях, вам нужно изменить свою функцию:

void get_pieces(struct Piece **pieces...)
{
    /* ... */
    *pieces = malloc(sizeof(struct Piece) * num_pieces);
}
4 голосов
/ 11 августа 2011

Это приводит к утечке памяти, потому что ваша функция get_pieces передает указатель на Pieces:

void get_pieces (struct Piece* pieces, ...

Затем вы выделяете память для pieces внутри этого метода. Когда он возвращается, эта выделенная память больше не доступна никому.

Это потому, что ваш указатель передается по значению - переназначение указателя не изменяет копию вызывающей функции. Чтобы повлиять на эту вызывающую функцию, вам нужно будет передать указатель на указатель, чтобы вы могли правильно назначить исходную копию:

void get_pieces (struct Piece** pieces, ...
     // ...
      *pieces = malloc(...

И, на месте звонка, передать адрес указателю.

0 голосов
/ 11 августа 2011

В вызове

get_pieces(t.pieces, &t.num_pieces, data)

вы передаете указатель t.pieces по значению, поэтому он копируется для использования в функции.Поскольку вы назначаете его внутри функции, но не снаружи, а теперь это два разных указателя, внешний указатель никогда не назначается.Указатель внутри функции уничтожается при разматывании стека, а выделенная память остается в куче, забытая.

Это можно исправить, изменив вызов на

get_pieces(&t.pieces, &t.num_pieces, data)
...