【发布时间】:2019-12-18 06:14:42
【问题描述】:
我正在努力解决这个问题。
如果我在 Linux 中使用 top 命令检查我的应用程序,我会发现 VIRT 始终相同(运行几天),而 RES 正在增加一点(在 4 字节和 32 字节之间)手术后。我每 60 分钟执行一次手术。
一个操作包括通过 SPI 读取一些帧,将它们添加到几个链表中,然后在另一个线程中提取它们。
我使用以下选项执行 Valgrind:
valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes -v ./application
一旦我关闭它(如果一切顺利,我的应用程序将永远运行)我检查泄漏,除了我没有关闭的线程之外我什么也看不到。仅可能在线程中丢失字节。绝对没有,也没有间接。
我不知道这是否正常。我过去曾使用 Valgrind 来发现一些漏洞,它一直运行良好,我很确定它现在也运行良好,但我无法解释 RES 问题。
我已经检查了链表,看看我是否留下了一些没有空闲的节点,但对我来说,这似乎是正确的。
我在一个数组中有 32 个链表。我这样做是为了使推送/弹出操作更容易,而无需 32 个单独的列表。我不知道这是否会导致问题。如果是这种情况,我将它们分开:
typedef struct PR_LL_M_node {
uint8_t val[60];
struct PR_LL_M_node *next;
} PR_LL_M_node_t;
pthread_mutex_t PR_LL_M_lock[32];
PR_LL_M_node_t *PR_LL_M_head[32];
uint16_t PR_LL_M_counter[32];
int16_t LL_M_InitLinkedList(uint8_t LL_M_number) {
if (pthread_mutex_init(&PR_LL_M_lock[LL_M_number], NULL) != 0) {
printf("Mutex LL M %d init failed\n", LL_M_number);
return -1;
}
PR_LL_M_ready[LL_M_number] = 0;
PR_LL_M_counter[LL_M_number] = 0;
PR_LL_M_head[LL_M_number] = NULL;
pthread_mutex_unlock(&PR_LL_M_lock[LL_M_number]);
return PR_LL_M_counter[LL_M_number];
}
int16_t LL_M_Push(uint8_t LL_M_number, uint8_t *LL_M_frame, uint16_t LL_M_size) {
pthread_mutex_lock(&PR_LL_M_lock[LL_M_number]);
PR_LL_M_node_t *current = PR_LL_M_head[LL_M_number];
if (current != NULL) {
while (current->next != NULL) {
current = current->next;
}
/* now we can add a new variable */
current->next = malloc(sizeof(PR_LL_M_node_t));
memset(current->next->val, 0x00, 60);
/* Clean buffer before using it */
memcpy(current->next->val, LL_M_frame, LL_M_size);
current->next->next = NULL;
} else {
PR_LL_M_head[LL_M_number] = malloc(sizeof(PR_LL_M_node_t));
memcpy(PR_LL_M_head[LL_M_number]->val, LL_M_frame, LL_M_size);
PR_LL_M_head[LL_M_number]->next = NULL;
}
PR_LL_M_counter[LL_M_number]++;
pthread_mutex_unlock(&PR_LL_M_lock[LL_M_number]);
return PR_LL_M_counter[LL_M_number];
}
int16_t LL_M_Pop(uint8_t LL_M_number, uint8_t *LL_M_frame) {
PR_LL_M_node_t *next_node = NULL;
pthread_mutex_lock(&PR_LL_M_lock[LL_M_number]);
if ((PR_LL_M_head[LL_M_number] == NULL)) {
pthread_mutex_unlock(&PR_LL_M_lock[LL_M_number]);
return -1;
}
if ((PR_LL_M_counter[LL_M_number] == 0)) {
pthread_mutex_unlock(&PR_LL_M_lock[LL_M_number]);
return -1;
}
next_node = PR_LL_M_head[LL_M_number]->next;
memcpy(LL_M_frame, PR_LL_M_head[LL_M_number]->val, 60);
free(PR_LL_M_head[LL_M_number]);
PR_LL_M_counter[LL_M_number]--;
PR_LL_M_head[LL_M_number] = next_node;
pthread_mutex_unlock(&PR_LL_M_lock[LL_M_number]);
return PR_LL_M_counter[LL_M_number];
}
这样我传递了我要管理的链表的编号并对其进行操作。你怎么看? RES 是一个真正的问题吗?我认为它可能与应用程序的其他部分有关,但我已经注释掉了大部分,如果使用 push/pop 操作,它总是会发生。如果我离开推送/弹出,RES 会保留它的号码。
当我提取值时,我使用do/while,直到我得到-1 作为弹出操作的响应。
【问题讨论】:
-
在 init 函数中调用
pthread_mutex_unlock会导致未定义的行为,因为此时互斥锁未锁定。 -
我删除了编辑。我将删除解锁并再次测试
-
尚不清楚问题出在哪里,但
return PR_LL_M_counter[LL_M_number];访问了临界区之外的共享资源,这可能导致竞争条件和 UB。 -
@n.m 我的问题是,在推送一些数据并弹出它们之后,我在 RES(顶部)中的值比以前更高。我是否也应该传递一个变量来读取关键部分内的该参数?
-
我在这里没有发现问题。 RES 是调入的内存量。您的操作系统决定何时调入或调出什么。 VIRT是内存总量,如果不改变,就没有内存泄漏。
标签: c memory-leaks linked-list