bui*_*ui3 4 c valgrind memory-leaks getline
我有一个关于函数的问题getline(),正如valgrind. 我发布了两个案例的代码并解释了行为。我希望有人能指出我正确的方向。
getline()在 while 循环中调用,读取缓冲区中文本文件的所有行。然后在循环结束时仅释放缓冲区一次:在这种情况下valgrind不会出现错误(不会发生泄漏)。
int main(int argc, char* argv[])
{
char* buffer = NULL;
size_t bufsize = 0;
ssize_t nbytes;
int counter = 0;
char error = 0;
FILE* input_fd = fopen(argv[1], "r");
while ((nbytes = getline(&buffer, &bufsize, input_fd)) != -1)
{
counter += 1;
}
free(buffer);
fclose(input_fd);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
同一个循环调用一个函数,该函数又调用getline(),传递相同的缓冲区。同样,缓冲区仅在循环结束时被释放一次,但在这种情况下会valgrind报告内存泄漏。事实上,让程序运行并查看 RSS,我可以看到它随着循环的进行而增加。请注意,在循环内添加一个 free(每个循环释放缓冲区)问题就会消失。这是代码。
int my_getline(FILE* lf_fd, char** lf_buffer)
{
ssize_t lf_nbytes = 0;
size_t lf_bufsiz = 0;
lf_nbytes = getline(lf_buffer, &lf_bufsiz, lf_fd);
if (lf_nbytes == -1)
return 1;
return 0;
}
int main(int argc, char* argv[])
{
char* lf_buffer = NULL;
size_t bufsize = 0;
ssize_t nbytes;
int counter = 0;
int new_line_counter = 0;
char error = 0;
FILE* lf_fd = fopen(argv[1], "r");
while ((my_getline(lf_fd, &lf_buffer)) == 0)
{
// Added to allow measuring the RSS
sleep(2);
// If I uncomment this, no memory leak occurs
//free(lf_buffer);
}
free(lf_buffer);
fclose(lf_fd);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
int main(int argc, char* argv[])
{
char* buffer = NULL;
size_t bufsize = 0;
ssize_t nbytes;
int counter = 0;
char error = 0;
FILE* input_fd = fopen(argv[1], "r");
while ((nbytes = getline(&buffer, &bufsize, input_fd)) != -1)
{
counter += 1;
}
free(buffer);
fclose(input_fd);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
第一个程序没问题。
第二个的问题来自缓冲区长度参数到getline(). 您my_getline()始终将其设置为 0,这意味着getline()每次都分配一个新缓冲区(至少,使用您正在使用的 glibc 实现;见下文)。将其更改为
int my_getline(FILE* lf_fd, char** lf_buffer, size_t* lf_bufsiz)
{
ssize_t lf_nbytes = 0;
lf_nbytes = getline(lf_buffer, lf_bufsiz, lf_fd);
if (lf_nbytes == -1)
return 1;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
并size_t在使用它时传递一个指向最初初始化为 0的变量的指针。现有bufsize变量 inmain()看起来适合使用:
//...
while ((my_getline(lf_fd, &lf_buffer, &bufsize)) == 0)
// ...
Run Code Online (Sandbox Code Playgroud)
虽然它很容易解决,但您遇到的内存泄漏似乎是getline().
从POSIX 文档:
如果
*lineptr是空指针或*lineptr指向的对象大小不足,则应分别按 分配malloc()对象或按 重新分配对象realloc(),以便对象大到足以容纳要分配的字符写给它...
或者,在调用之前
getline(),*lineptr可以包含一个指向malloc(3)分配的缓冲区*n字节大小的指针。 如果缓冲区不足以容纳该行,请getline()realloc(3)根据需要使用、更新*lineptr和调整其大小*n。
这些表明,在您遇到的情况下,您将有效的非NULL指针传递给内存并说它的长度为 0,则应该使用该函数realloc()来调整它的大小。但是,glibc 实现会检查*lineptr == NULL || *n == 0,如果为真,则*lineptr使用新分配的缓冲区覆盖,从而导致您看到的泄漏。比较NetBSD 实现,它realloc()用于所有分配(realloc(NULL, x)相当于malloc(x)),因此不会导致原始代码泄漏。这并不理想,因为它会realloc()在每次使用时导致,而不是仅在缓冲区不够大以容纳当前行时(与上面的固定版本不同),但它可以工作。
| 归档时间: |
|
| 查看次数: |
236 次 |
| 最近记录: |