我已经注意到我一直在测试的程序在两个不同的点上泄漏内存,无论我是否呼叫free().我不明白为什么会发生这种情况,也不知道如何才能修复它.

我正在使用Leaks来测试内存泄漏:我的机器没有可用的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;
}

Uncts.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

推荐答案

在您的printwords函数中,您在以下行中分配内存:

char* word= calloc(1, sizeof(char)*BUFSIZE);

在函数接近尾声时使用attempt释放该内存,方法是:

free(word);

然而,在该点(即,当while(1)循环已被中断时),word指针106 NULL,因为该循环的唯一出路是在if(word==NULL && tk) break;行中.请记住,使用NULL参数调用free函数并不是错误的,并且具有定义良好的(根据C标准)行为:它什么都不做.

我不确定为什么要进行这种分配(可能是为了将非空指针传递给pop_head函数);但是,如果要这样做,应该将其分配给different变量,然后将其复制到循环中使用的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;
}

或者,您可以在pop_head函数内处理分配的char缓冲区的free()(例如,在设置*val = NULL;并返回之前使用free(*val)),但这may会干扰列表删除过程的正常工作.

请注意,在tokenizer函数中,您的bfr缓冲区也存在完全相同的问题,补救方法也是相同的.

C++相关问答推荐

找出文件是否包含给定的文件签名

如何在C中只使用一个带双方括号([i][j])访问语法的malloc来分配动态大小的2d数组?

显式地将值转换为它从函数返回的类型的含义是什么?

C:二进制搜索和二进制插入

GCC预处理宏和#杂注GCC展开

如何在IF语句中正确使用0.0

变量>;-1如何在C中准确求值?

二进制计算器与gmp

我在这里正确地解释了C操作顺序吗?

如何在C中打印包含扫描字符和整数的语句?

函数的限制限定指针参数允许优化调用方函数吗?

什么是.c.h文件?

如何在C-函数中混合使用C代码和ASM?

无法识别C编程语言的语法,如书中所示

C语言中的指针和多维数组

C struct 中的冒泡排序

为什么 int32_t 和 int16_t 在 printf 输出中具有相同的位数?

使用fread()函数读取txt文件

是否可以在多字 C 类型中的任何位置混合存储和类型限定符?

我怎样才能用c语言正常运行这两个进程?