内存泄漏:块仍然可以访问 - 如何解决?
Memory leak: blocks are still reachable - How to solve it?
我在这里找到了一些类似的主题:
Valgrind - blocks still reachable due to?
或在这里:
Still Reachable Leak detected by Valgrind
但是 none 提供了解决方案。因此,我想再次提出这个问题。
这是 valgrind 的结果:
==403== HEAP SUMMARY:
==403== in use at exit: 7,791,056 bytes in 139,126 blocks
==403== total heap usage: 143,096 allocs, 3,970 frees, 8,023,256 bytes allocated
==403==
==403== 7,791,056 bytes in 139,126 blocks are still reachable in loss record 1 of 1
==403== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==403== by 0x401BBE: load (dictionary.c:121)
这是我为新节点分配内存的代码:
#include <stdbool.h>
#include <stdio.h>
#include "dictionary.h"
#include <ctype.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
// Represents a node in a hash table
typedef struct node
{
char word[LENGTH + 1];
struct node *next;
}
node;
// ADDITIONAL functions
bool free_list(node *w);
unsigned int numeric(char c);
// Number of buckets in hash table
const unsigned int N = 26 * 28 * 28;
// Initialize number of word count in dictionary
int word_count = 0;
// Hash table
node *table[N];
// Returns true if word is in dictionary, else false
bool check(const char *word)
{
// TODO: initiate a node before looping
node *n = table[hash(word)];
// Checks if malloc succeeded, returns false if not
while (true)
{
if (n == NULL)
{
return false;
}
else if (strcasecmp(n->word, word) == 0)
{
return true;
}
else
{
n = n->next;
}
}
}
// Hashes word to a number
unsigned int hash(const char *word)
{
// TODO
int ret;
ret = tolower(word[0]) - 97 + 26 * numeric(word[1]);
if (word[1] != '[=11=]')
{
ret += 26 * 28 * numeric(word[2]);
}
return ret;
}
// ADDITION: Numeric char value
unsigned int numeric(char c)
{
int ret;
if (isalpha(c))
{
ret = (tolower(c) - 96);
}
else if (c == '[=11=]')
{
ret = 0;
}
else
{
ret = 27;
}
return ret;
}
// Loads dictionary into memory, returning true if successful, else false
bool load(const char *dictionary)
{
// TODO: Open file
FILE *dict = fopen(dictionary, "r");
if (dict == NULL)
{
printf("Could not open dictionary.\n");
return false;
}
//Initialize the list to be NULL
for (int i = 0; i < N; i += 1)
{
table[i] = NULL;
}
// COPY words in dictionary to hash table
char c;
char tmp[LENGTH + 1];
int index = 0;
while (fread(&c, sizeof(char), 1, dict))
{
if (c != '\n')
{
tmp[index] = c;
index += 1;
}
else // means this is a full word
{
// Terminate current word
tmp[index] = '[=11=]';
// Put the word to the hash
// allocate memory to a new node
node *n = malloc(sizeof(node));
// Checks if malloc succeeded, returns false if not
if (n == NULL)
{
unload();
return false;
}
// assign values to new node
n->next = table[hash(tmp)];
strcpy(n->word, tmp);
// make the hash point to the new node
table[hash(tmp)] = n;
// Clear the tmp array for next word
for (int i = 0; i < index + 1; i += 1)
{
tmp[index] = 0;
}
word_count += 1; //Increase word count for size function
index = 0;
}
}
fclose(dict);
return true;
}
// Returns number of words in dictionary if loaded, else 0 if not yet loaded
unsigned int size(void)
{
// TODO
return word_count;
}
// Unloads dictionary from memory, returning true if successful, else false
bool unload(void)
{
// TODO
for (int i = 0; i < N; i += 1)
{
free_list(table[i]);
}
return true;
}
// Create free linked-list function
bool free_list(node *w)
{
if (w == NULL)
{
return true;
}
else if (w->next == NULL)
{
free(w);
return true;
}
else
{
free_list(w->next);
return true;
}
}
HEAP SUMMARY报告问题的第121行是新节点的malloc行,在load()函数中:node *n = malloc(sizeof(node));
你能告诉我为什么会导致内存泄漏以及我该如何解决这个问题吗?
你的 free_list
函数有一个问题。
这个递归函数只会释放列表中的最后一个节点。这可以重写为不是递归的,但你可能想要在最后一个“else”代码块中是
free_list(w->next);
free(w);
return true;
顺便说一句,为什么这个函数有一个 return 值?它始终 return 为真,并且您永远不会在调用函数时检查 return 值。
你的 free 函数只释放最后一个元素的内存:
bool free_list(node *w)
{
if (w == NULL) // empty : no free
{
return true;
}
else if (w->next == NULL) // free last element
{
free(w);
return true;
}
else
{
free_list(w->next); // try to free next element but not current
return true;
}
}
应修改为:
bool free_list(node *w)
{
if (w == NULL)
{
return true;
}
// free next elements
if (w->next != NULL)
{
free_list(w->next);
}
// free current
free(w);
return true;
}
我在这里找到了一些类似的主题: Valgrind - blocks still reachable due to? 或在这里: Still Reachable Leak detected by Valgrind 但是 none 提供了解决方案。因此,我想再次提出这个问题。
这是 valgrind 的结果:
==403== HEAP SUMMARY:
==403== in use at exit: 7,791,056 bytes in 139,126 blocks
==403== total heap usage: 143,096 allocs, 3,970 frees, 8,023,256 bytes allocated
==403==
==403== 7,791,056 bytes in 139,126 blocks are still reachable in loss record 1 of 1
==403== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==403== by 0x401BBE: load (dictionary.c:121)
这是我为新节点分配内存的代码:
#include <stdbool.h>
#include <stdio.h>
#include "dictionary.h"
#include <ctype.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
// Represents a node in a hash table
typedef struct node
{
char word[LENGTH + 1];
struct node *next;
}
node;
// ADDITIONAL functions
bool free_list(node *w);
unsigned int numeric(char c);
// Number of buckets in hash table
const unsigned int N = 26 * 28 * 28;
// Initialize number of word count in dictionary
int word_count = 0;
// Hash table
node *table[N];
// Returns true if word is in dictionary, else false
bool check(const char *word)
{
// TODO: initiate a node before looping
node *n = table[hash(word)];
// Checks if malloc succeeded, returns false if not
while (true)
{
if (n == NULL)
{
return false;
}
else if (strcasecmp(n->word, word) == 0)
{
return true;
}
else
{
n = n->next;
}
}
}
// Hashes word to a number
unsigned int hash(const char *word)
{
// TODO
int ret;
ret = tolower(word[0]) - 97 + 26 * numeric(word[1]);
if (word[1] != '[=11=]')
{
ret += 26 * 28 * numeric(word[2]);
}
return ret;
}
// ADDITION: Numeric char value
unsigned int numeric(char c)
{
int ret;
if (isalpha(c))
{
ret = (tolower(c) - 96);
}
else if (c == '[=11=]')
{
ret = 0;
}
else
{
ret = 27;
}
return ret;
}
// Loads dictionary into memory, returning true if successful, else false
bool load(const char *dictionary)
{
// TODO: Open file
FILE *dict = fopen(dictionary, "r");
if (dict == NULL)
{
printf("Could not open dictionary.\n");
return false;
}
//Initialize the list to be NULL
for (int i = 0; i < N; i += 1)
{
table[i] = NULL;
}
// COPY words in dictionary to hash table
char c;
char tmp[LENGTH + 1];
int index = 0;
while (fread(&c, sizeof(char), 1, dict))
{
if (c != '\n')
{
tmp[index] = c;
index += 1;
}
else // means this is a full word
{
// Terminate current word
tmp[index] = '[=11=]';
// Put the word to the hash
// allocate memory to a new node
node *n = malloc(sizeof(node));
// Checks if malloc succeeded, returns false if not
if (n == NULL)
{
unload();
return false;
}
// assign values to new node
n->next = table[hash(tmp)];
strcpy(n->word, tmp);
// make the hash point to the new node
table[hash(tmp)] = n;
// Clear the tmp array for next word
for (int i = 0; i < index + 1; i += 1)
{
tmp[index] = 0;
}
word_count += 1; //Increase word count for size function
index = 0;
}
}
fclose(dict);
return true;
}
// Returns number of words in dictionary if loaded, else 0 if not yet loaded
unsigned int size(void)
{
// TODO
return word_count;
}
// Unloads dictionary from memory, returning true if successful, else false
bool unload(void)
{
// TODO
for (int i = 0; i < N; i += 1)
{
free_list(table[i]);
}
return true;
}
// Create free linked-list function
bool free_list(node *w)
{
if (w == NULL)
{
return true;
}
else if (w->next == NULL)
{
free(w);
return true;
}
else
{
free_list(w->next);
return true;
}
}
HEAP SUMMARY报告问题的第121行是新节点的malloc行,在load()函数中:node *n = malloc(sizeof(node));
你能告诉我为什么会导致内存泄漏以及我该如何解决这个问题吗?
你的 free_list
函数有一个问题。
这个递归函数只会释放列表中的最后一个节点。这可以重写为不是递归的,但你可能想要在最后一个“else”代码块中是
free_list(w->next);
free(w);
return true;
顺便说一句,为什么这个函数有一个 return 值?它始终 return 为真,并且您永远不会在调用函数时检查 return 值。
你的 free 函数只释放最后一个元素的内存:
bool free_list(node *w)
{
if (w == NULL) // empty : no free
{
return true;
}
else if (w->next == NULL) // free last element
{
free(w);
return true;
}
else
{
free_list(w->next); // try to free next element but not current
return true;
}
}
应修改为:
bool free_list(node *w)
{
if (w == NULL)
{
return true;
}
// free next elements
if (w->next != NULL)
{
free_list(w->next);
}
// free current
free(w);
return true;
}