valgrind的错误?或者我的错误?

时间:2015-04-14 12:04:37

标签: c memory-leaks valgrind

所以我写了一个有趣的玩具程序,在那一刻我完成了调试思考我终于把一切都搞定了,最后一次检查valgrind给了我2个错误,因为没有释放2块内存。但错误信息对我来说真的没有意义。

==7419== 80 bytes in 1 blocks are definitely lost in loss record 1 of 2
==7419==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7419==    by 0x400C77: mj_Malloc (mj.c:19)
==7419==    by 0x401761: main (choco.c:93)
==7419== 
==7419== 80 bytes in 1 blocks are definitely lost in loss record 2 of 2
==7419==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7419==    by 0x400C77: mj_Malloc (mj.c:19)
==7419==    by 0x401776: main (choco.c:94)
==7419== 
==7419== LEAK SUMMARY:
==7419==    definitely lost: 160 bytes in 2 blocks

main中的第94行和第93行是

mj_Thread *chocolateMakers = mj_Malloc(nMakers * sizeof *chocolateMakers);
mj_Thread *chocolateEaters = mj_Malloc(nEaters * sizeof *chocolateEaters);

释放
mj_Free(chocolateEaters);
mj_Free(chocolateMakers);

mj_Mallocmj_Free是用于错误检查的简单包装器。 (mj_Free表示一致性)

void *mj_Malloc(size_t size) {
    void *p = malloc(size);
    if (p == NULL) {
        mj_Error("heap allocation failed");
    }
    return p;
}

void mj_Free(void *p) {
    free(p);
}

如果需要,您可以看到以下整个代码。

choco.c

#include "../mj.c"

typedef struct {
    int n;
    mj_BlockingQueue orderQueue;
    mj_BlockingQueue deliveryQueue;
} *ChocolateArgument;

ChocolateArgument ChocolateArgumentCreate(int n, mj_BlockingQueue orderQueue, mj_BlockingQueue deliveryQueue) {
    ChocolateArgument this = mj_Malloc(sizeof *this);
    this->n = n;
    this->orderQueue = orderQueue;
    this->deliveryQueue = deliveryQueue;
    return this;
}

int MakeChocolates(void *data) {
    ChocolateArgument argument = (ChocolateArgument)data;
    while (true) {
        if (mj_BlockingQueueOut(argument->orderQueue) != NULL) {
            printf("chocolate maker %i going home\n", argument->n);
            break;
        }
        int milli = mj_RandomInt(1, 1000);
        mj_Sleep(milli);
        printf("new chocolate (maker %i, %.3f seconds)\n", argument->n, (double)milli / 1000.0);
        int *pMakerNumber = mj_Malloc(sizeof *pMakerNumber);
        *pMakerNumber = argument->n;
        mj_BlockingQueueIn(argument->deliveryQueue, pMakerNumber);
    }
    mj_Free(data);
    return EXIT_SUCCESS;
}

void HireChocolateMakers(mj_Thread **pMakers, int nMakers, mj_BlockingQueue orderQueue, mj_BlockingQueue deliveryQueue) {
    *pMakers = mj_Malloc(nMakers * sizeof **pMakers);
    for (int i = 0; i < nMakers; i += 1) {
        ChocolateArgument argument = ChocolateArgumentCreate(i + 1, orderQueue, deliveryQueue);
        (*pMakers)[i] = mj_ThreadCreate(MakeChocolates, argument);
    }
    printf("%i chocolate makers hired\n", nMakers);
}

int EatChocolates(void *data) {
    ChocolateArgument argument = (ChocolateArgument)data;
    int nOrders = mj_RandomInt(1, 10);
    for (int i = 0; i < nOrders; i += 1) {
        mj_BlockingQueueIn(argument->orderQueue, NULL);
    }
    printf("chocolate eater %i ordered %i chocolates\n", argument->n, nOrders);
    for (int i = 1; i <= nOrders; i += 1) {
        int *pMakerNumber = mj_BlockingQueueOut(argument->deliveryQueue);
        printf("maker %i -> eater %i (%i / %i)\n", *pMakerNumber, argument->n, i, nOrders);
        free(pMakerNumber);
    }
    printf("chocolate eater %i is satisfied\n", argument->n);
    mj_Free(data);
    return EXIT_SUCCESS;
}

void OrderChocolates(mj_Thread **pEaters, int nEaters, mj_BlockingQueue orderQueue, mj_BlockingQueue deliveryQueue) {
    *pEaters = mj_Malloc(nEaters * sizeof **pEaters);
    for (int i = 0; i < nEaters; i += 1) {
        ChocolateArgument argument = ChocolateArgumentCreate(i + 1, orderQueue, deliveryQueue);
        (*pEaters)[i] = mj_ThreadCreate(EatChocolates, argument);
    }
}

void GoHome(mj_Thread *eaters, int nEaters, mj_Thread *makers, int nMakers, mj_BlockingQueue orderQueue) {
    for (int i = 0; i < nEaters; i += 1) {
        mj_ThreadWait(eaters[i]);
        mj_ThreadDelete(eaters[i]);
    }
    printf("all chocolate eaters are satisfied\n");
    for (int i = 0; i < nMakers; i += 1) {
        mj_BlockingQueueIn(orderQueue, NULL + 1);
    }
    for (int i = 0; i < nMakers; i += 1) {
        mj_ThreadWait(makers[i]);
        mj_ThreadDelete(makers[i]);
    }
}

int main(int argc, char **argv) {
    if (argc != 3) {
        mj_Error("not enough arguments");
    }
    int nMakers = atoi(argv[1]);
    int nEaters = atoi(argv[2]);
    mj_RandomSeed();
    mj_BlockingQueue orderQueue = mj_BlockingQueueCreate();
    mj_BlockingQueue deliveryQueue = mj_BlockingQueueCreate();
    mj_Thread *chocolateMakers = mj_Malloc(nMakers * sizeof *chocolateMakers);
    mj_Thread *chocolateEaters = mj_Malloc(nEaters * sizeof *chocolateEaters);
    HireChocolateMakers(&chocolateMakers, nMakers, orderQueue, deliveryQueue);
    OrderChocolates(&chocolateEaters, nEaters, orderQueue, deliveryQueue);
    GoHome(chocolateEaters, nEaters, chocolateMakers, nMakers, orderQueue);
    mj_BlockingQueueDelete(orderQueue);
    mj_BlockingQueueDelete(deliveryQueue);
    mj_Free(chocolateEaters);
    mj_Free(chocolateMakers);
    return 0;
}

mj.c

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <inttypes.h>
#include <limits.h>
#include <math.h>
#include <time.h>

#include <pthread.h>
#include <semaphore.h>

void mj_Error(char *errorMessage) {
    fprintf(stderr, "%s\n", errorMessage);
    exit(EXIT_FAILURE);
}

void *mj_Malloc(size_t size) {
    void *p = malloc(size);
    if (p == NULL) {
        mj_Error("heap allocation failed");
    }
    return p;
}

void mj_Free(void *p) {
    free(p);
}

typedef struct mj_QueueElement {
    void *data;
    struct mj_QueueElement *next;
} *mj_QueueElement;

mj_QueueElement mj_QueueElementCreate(void) {
    mj_QueueElement this = mj_Malloc(sizeof *this);
    return this;
}

void mj_QueueElementDelete(mj_QueueElement this) {
    mj_Free(this);
}

typedef struct {
    mj_QueueElement first;
    mj_QueueElement last;
} *mj_Queue;

mj_Queue mj_QueueCreate(void) {
    mj_Queue this = mj_Malloc(sizeof *this);
    this->first = mj_QueueElementCreate();
    this->last = this->first;
    return this;
}

void mj_QueueDelete(mj_Queue this) {
    mj_QueueElementDelete(this->first);
    mj_Free(this);
}

void mj_QueueIn(mj_Queue this, void *data) {
    this->last->data = data;
    this->last->next = mj_QueueElementCreate();
    this->last = this->last->next;
}

void *mj_QueueOut(mj_Queue this) {
    mj_QueueElement temp = this->first;
    void *data = temp->data;
    this->first = this->first->next;
    mj_QueueElementDelete(temp);
    return data;
}

typedef pthread_mutex_t *mj_Mutex;

mj_Mutex mj_MutexCreate(void) {
    mj_Mutex this = mj_Malloc(sizeof *this);
    pthread_mutex_init(this, NULL);
    return this;
}

void mj_MutexDelete(mj_Mutex this) {
    pthread_mutex_destroy(this);
    mj_Free(this);
}

void mj_MutexLock(mj_Mutex this) {
    pthread_mutex_lock(this);
}

void mj_MutexUnlock(mj_Mutex this) {
    pthread_mutex_unlock(this);
}

typedef sem_t *mj_Semaphore;

mj_Semaphore mj_SemaphoreCreate(int n) {
    mj_Semaphore this = mj_Malloc(sizeof *this);
    sem_init(this, 0, n);
    return this;
}

void mj_SemaphoreDelete(mj_Semaphore this) {
    sem_destroy(this);
    mj_Free(this);
}

void mj_SemaphoreUp(mj_Semaphore this) {
    sem_post(this);
}

void mj_SemaphoreDown(mj_Semaphore this) {
    sem_wait(this);
}

typedef struct {
    mj_Queue queue;
    mj_Mutex inLock;
    mj_Mutex outLock;
    mj_Semaphore emptyBlocker;
} *mj_BlockingQueue;

mj_BlockingQueue mj_BlockingQueueCreate(void) {
    mj_BlockingQueue this = mj_Malloc(sizeof *this);
    this->queue = mj_QueueCreate();
    this->inLock = mj_MutexCreate();
    this->outLock = mj_MutexCreate();
    this->emptyBlocker = mj_SemaphoreCreate(0);
    return this;
}

void mj_BlockingQueueDelete(mj_BlockingQueue this) {
    mj_QueueDelete(this->queue);
    mj_MutexDelete(this->inLock);
    mj_MutexDelete(this->outLock);
    mj_SemaphoreDelete(this->emptyBlocker);
    mj_Free(this);
}

void mj_BlockingQueueIn(mj_BlockingQueue this, void *data) {
    mj_MutexLock(this->inLock);
    mj_QueueIn(this->queue, data);
    mj_SemaphoreUp(this->emptyBlocker);
    mj_MutexUnlock(this->inLock);
}

void *mj_BlockingQueueOut(mj_BlockingQueue this) {
    mj_MutexLock(this->outLock);
    mj_SemaphoreDown(this->emptyBlocker);
    void *data = mj_QueueOut(this->queue);
    mj_MutexUnlock(this->outLock);
    return data;
}

typedef pthread_t *mj_Thread;

typedef struct {
    int (*function)(void *);
    void *argument;
} *mj_ThreadInfo;

mj_ThreadInfo mj_ThreadInfoCreate(int (*function)(void *), void *argument) {
    mj_ThreadInfo this = mj_Malloc(sizeof *this);
    this->function = function;
    this->argument = argument;
    return this;
}

void *mj_ThreadFunction(void *data) {
    mj_ThreadInfo info = (mj_ThreadInfo)data;
    info->function(info->argument);
    mj_Free(data);
    return NULL;
}

mj_Thread mj_ThreadCreate(int (*function)(void *), void *argument) {
    mj_Thread this = mj_Malloc(sizeof *this);
    mj_ThreadInfo info = mj_ThreadInfoCreate(function, argument);
    if (pthread_create(this, NULL, mj_ThreadFunction, info) != 0) {
        mj_Error("failed to create thread");
    }
    return this;
}

void mj_ThreadDelete(mj_Thread this) {
    mj_Free(this);
}

void mj_ThreadWait(mj_Thread this) {
    pthread_join(*this, NULL);
}

void mj_Sleep(int milli) {
    struct timespec time;
    time.tv_sec = milli / 1000;
    time.tv_nsec = (milli % 1000) * 1000000;
    nanosleep(&time, NULL);
}

uint64_t mj_RandomInt_s;
uint64_t mj_RandomInt_s2;

void mj_RandomSeed(void) {
    srand((unsigned)time(NULL));
    mj_RandomInt_s = rand() * rand();
    mj_RandomInt_s2 = rand() * rand() * rand();
}

int mj_RandomInt(int from, int to) {
    if (from > to) {
        mj_Error("invalid arguments");
    }
    uint64_t x = mj_RandomInt_s;
    uint64_t y = mj_RandomInt_s2;
    mj_RandomInt_s = y;
    x ^= x << 23;
    x ^= x >> 17;
    x ^= y ^ (y >> 26);
    mj_RandomInt_s2 = x;
    return (int)((x + y) % (uint64_t)(to - from + 1)) + from;
}

1 个答案:

答案 0 :(得分:3)

您分配chocolateMakers两次(第93行,第36行)和chocolateEaters两次(第94行第62行,第62行)。在这两种情况下,您都会覆盖第一次分配产生的指针和第二次分配产生的指针。当你释放分配的内存时,你只需要使用第二次分配的指针进行一次。第一次分配的指针丢失,分配的内存永远不会被释放。