提问人:DravStart 提问时间:8/29/2023 最后编辑:Adrian MoleDravStart 更新时间:8/30/2023 访问量:101
释放后内存泄漏?
memory leak after free?
问:
我注意到我一直在测试的程序在两个不同的点泄漏内存,无论我是否调用。我不明白为什么会发生这种情况以及如何修复它。free()
我正在使用泄漏来测试内存泄漏:我的机器没有可用的 Valgrind。
报告如下:
leaks Report Version: 4.0, multi-line stacks
Process 21334: 226 nodes malloced for 18 KB
Process 21334: 2 leaks for 544 total leaked bytes.
STACK OF 1 INSTANCE OF 'ROOT LEAK: <malloc in tokenizer>':
3 libsystem_pthread.dylib 0x18d51eda0 thread_start + 8
2 libsystem_pthread.dylib 0x18d523fa8 _pthread_start + 148
1 a.out 0x102c13c10 tokenizer + 36
0 libsystem_malloc.dylib 0x18d364d88 _malloc_zone_malloc_instrumented_or_legacy + 128
====
1 (272 bytes) ROOT LEAK: <malloc in tokenizer 0x120004080> [272]
STACK OF 1 INSTANCE OF 'ROOT LEAK: <calloc in printwords>':
3 libsystem_pthread.dylib 0x18d51eda0 thread_start + 8
2 libsystem_pthread.dylib 0x18d523fa8 _pthread_start + 148
1 a.out 0x102c13d4c printwords + 40
0 libsystem_malloc.dylib 0x18d364eb0 _malloc_zone_calloc_instrumented_or_legacy + 92
====
1 (272 bytes) ROOT LEAK: <calloc in printwords 0x11ef041d0> [272]
它是一个多线程程序,读取文本文件,分离单词,然后打印它们。这个版本不打印单词,但内存泄漏完全相同(我已经测试过了)。
法典:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include <pthread.h>
#include <string.h>
#include "functs.h"
pthread_t *thpool;
Deque_t* deque_12;
Deque_t* deque_23;
void* readfile(void* arg);
void* tokenizer();
void* printwords();
char rd;
char tk;
void init(){
deque_12 = new_deque();
deque_23 = new_deque();
rd = 0; //lines read
tk = 0; //all lines tokenized
}
int main(int argc, char *argv[]){
char* filename = "loremIpsum.txt";
init();
thpool = malloc(sizeof(pthread_t)*3);
thread_create(&thpool[0],/*attrs*/ NULL, readfile, (void*)filename);
thread_create(&thpool[1],/*attrs*/ NULL, tokenizer, /*args*/NULL);
thread_create(&thpool[2],/*attrs*/ NULL, printwords, /*args*/NULL);
for(int i=0; i<3; i++)
thread_join(thpool[i], NULL);
free_deque(deque_12,1);
free_deque(deque_23,0);
free(thpool);
}
void* readfile(void* arg){
FILE* fp= fopen((char*)arg, "r");
char* line= calloc(1,sizeof(char)*BUFSIZE);
while(fgets(line, BUFSIZE, fp)!=NULL){
push_tail(deque_12, (void*)line);
line= calloc(1,sizeof(char)*BUFSIZE);
}
rd=1;
printf("1: File read\n");
fclose(fp);
free(line);
return NULL;
}
void* tokenizer(){
struct timespec t = {0,1000000};
while(isEmpty(deque_12))
nanosleep(&t, NULL);
char* bfr = malloc(sizeof(char)*BUFSIZE); //memory leak
while(1){
pop_head(deque_12, (void*)&bfr,1);
if(bfr==NULL && rd) break;
else if(bfr==NULL){
nanosleep(&t, NULL);
continue;
}
char* state;
char* token = strtok_r(bfr, " ",&state);
while(token!=NULL){
push_tail(deque_23, (void*)token);
token = strtok_r(NULL, " ",&state);
}
}
free(bfr);
tk=1;
puts("2: Tokenized");
return NULL;
}
void* printwords(){
struct timespec t = {0,1000000};
char* word= calloc(1, sizeof(char)*BUFSIZE); //memory leak
while(1){
pop_head(deque_23, (void*)&word,0);
if(word==NULL && tk) break;
else if(word==NULL){
nanosleep(&t, NULL);
continue;
}
printf(">%s\n",word);
fflush(stdout);
}
puts("3: all words printed");
free(word);
return NULL;
}
functs.h:
#ifndef _FUNCTS_H
#define _FUNCTS_H
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include<unistd.h>
#include <errno.h>
#ifndef BUFSIZE
#define BUFSIZE 256
#endif
void thread_create(pthread_t *tid,const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg){
int err;
if((err = pthread_create(tid, attr, start_routine, arg)) != 0){
perror("pthread_create");
errno = err;
pthread_exit(&errno);
}
}
void thread_join(pthread_t tid, void **retval){
int err;
if((err = pthread_join(tid, retval)) != 0){
fprintf(stderr,"FATAL_ERROR: thread_join");
errno = err;
pthread_exit(&errno);
}
}
void mtx_lock(pthread_mutex_t *mtx_ptr){
int err;
if((err = pthread_mutex_lock(mtx_ptr)) != 0){
puts("mutex_lock");
errno = err;
pthread_exit(&errno);
}
}
void mtx_unlock(pthread_mutex_t *mtx_ptr){
int err;
if((err = pthread_mutex_unlock(mtx_ptr)) != 0){
perror("mutex_unlock");
errno = err;
pthread_exit(&errno);
}
}
typedef struct node{
void* data;
struct node *next;
struct node *prev;
}Node_t;
typedef struct deque{
Node_t *head;
Node_t *tail;
pthread_mutex_t mtx;
}Deque_t;
Deque_t* new_deque(){
Deque_t* d = malloc(sizeof(Deque_t));
d->head = NULL;
d->tail = NULL;
pthread_mutex_init(&(d->mtx), NULL);
return d;
}
int isEmpty(Deque_t *d){
return (d->head == NULL);
}
void push_tail(Deque_t* d, void* data){
Node_t *newNode = malloc(sizeof(Node_t));
newNode->data = data;
newNode->next = NULL;
mtx_lock(&(d->mtx));
if(isEmpty(d)){
newNode->prev = NULL;
d->head = newNode;
}
else{
newNode->prev = d->tail;
d->tail->next = newNode;
}
d->tail = newNode;
mtx_unlock(&(d->mtx));
}
void pop_head(Deque_t* d, void** val, int ismallocd){
mtx_lock(&(d->mtx));
if(isEmpty(d)){
mtx_unlock(&(d->mtx));
*val = NULL;
return;
}
Node_t *tmp = d->head;
*val = d->head->data;
if(d->head == d->tail){
d->head = NULL;
d->tail = NULL;
}
else{
d->head = d->head->next;
d->head->prev = NULL;
}
mtx_unlock(&(d->mtx));
if(ismallocd) free(tmp->data);
free(tmp);
}
void free_deque(Deque_t* d, int ismallocd){
Node_t* tmp;
while(d->head != NULL){
tmp = d->head;
d->head = d->head->next;
if(ismallocd) free(tmp->data);
free(tmp);
}
free(d);
}
#endif
答:
0赞
Adrian Mole
8/30/2023
#1
在函数中,按以下行分配内存:printwords
char* word= calloc(1, sizeof(char)*BUFSIZE);
您尝试在函数末尾释放该内存,并执行以下操作:
free(word);
但是,到那时(即当循环被破坏时),指针必须是 ,因为离开该循环的唯一方法就是在行中。请记住,使用参数调用函数不是错误,并且具有明确定义的(根据 C 标准)行为:它什么都不做。while(1)
word
NULL
if(word==NULL && tk) break;
free
NULL
我不完全确定您为什么要进行这种分配(可能,以便您可以将非空指针传递给函数);但是,如果要这样做,则应将其分配给其他变量,然后将其复制到循环中使用的指针。pop_head
word
以下是执行此操作的一种方法:
void* printwords()
{
struct timespec t = {0,1000000};
char* temp = calloc(1, sizeof(char)*BUFSIZE);
char* word = temp; // We can use that local allocation but we MUST remember it!
while(1) {
pop_head(deque_23, (void*)&word,0);
if(word==NULL && tk) break;
else if(word==NULL){
nanosleep(&t, NULL);
continue;
}
printf(">%s\n",word);
fflush(stdout);
}
puts("3: all words printed");
// free(word); // WRONG! At this point, "word" is NULL
free(temp); // Should work!
return NULL;
}
或者,您可以在函数中处理该分配的缓冲区(例如,在设置和返回之前),但这可能会干扰列表删除过程的正常工作。free()
char
pop_head
free(*val)
*val = NULL;
请注意,您的缓冲区在函数中遇到了完全相同的问题,并且补救措施是相同的。bfr
tokenizer
评论
0赞
DravStart
8/30/2023
没有想到我可以在没有分配lmao的情况下声明指针,这真的是一个被忽视的错误。如果我需要分配它,我现在知道我应该事先创建一个临时变量。多谢!
上一个:使用矩阵时的 Sprintf
评论
if(bfr==NULL && rd) break