Ready to use: share a small tool to check for memory leaks

【Function description】

        During the development of embedded system applications, memory leakage is a very serious and headache problem. Of course, there are a lot of professional tools and software to check for memory leaks, I use memwatch and valgrind more.

        These tools are mainly used to check memory leaks during the development process. However, if all the programs have been developed and the integration test is started, it is still found that there is a continuous decrease in system resources, then how to deal with it?

        The small tools provided here are used to deal with this situation: you can monitor the system resources used by those processes that you suspect may have memory leaks.

        Especially when a system is developed by multiple people and composed of multiple processes, if there is a resource leak, who do you say should be suspected first? Who should be asked to check whether there is a problem with his program first? Wrangling often happens, and the estrangement between the little friends has planted the seeds in the subconscious.

        At this point, the data output by the monitoring program is most useful!

 

 

【test environment】

1. x86 system

    I tested it under Ubuntu 16.04, using the gcc compiler that comes with the system.

2. Embedded system

    Just change the compiler to the corresponding cross-compiler.

 

【Code download】

1. SkyDrive

    https://pan.baidu.com/s/1yNrjQ6var8xokAJWEsFYFw  

    passwd:uqbh

 

2. File description

    The core code is just one file: memory_trace.c, and the other two are compilation scripts.

/**
 * @brief: 这个小工具用来监控系统中一些进程的资源使用情况,
 *			可以用来检查程序中是否存在内存泄露。
 * 
 * @author: 微信 captain5780
 * @email:  [email protected]
 *
 * @note: ./memory_trace <进程名称1> <进程名称2> <进程名称3>
 */

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define TRACE_ITEM_NUM		4
#define PROCESS_MAX			20
#define PROCESS_NAME_LEN	128
#define BUF_LEN				512

// 需要监控的资源名称
char *TraceItem[TRACE_ITEM_NUM] = 
	{"VmSize", "VmRSS", "VmStk", "VmData"};

// 保存需要监控的进程名称
char *ProcessList[PROCESS_MAX];

// 打印消息,在实际项目中可以利用 zlog 等日志工具来记录到文件系统中。
static void log_msg(const char *msg)
{
	printf("%s", msg);
}

int main(int argc, char *argv[])
{
	// 检查最大监控的进程个数
	if (argc >= PROCESS_MAX) {
		printf("too many process \n");
		exit(-1);
	}

	// 提取命令行参数传入的进程名称,保存在 ProcessList 中。
	int i, k, count;
	for (i = 0, count = 0; i < argc - 1; i++) {
		count++;
		ProcessList[i] = (char *)malloc(PROCESS_NAME_LEN);
		memset(ProcessList[i], 0, PROCESS_NAME_LEN);
		sprintf(ProcessList[i], "%s", argv[i + 1]);
	}

	time_t rawtime;
	struct tm *timeinfo;
	char *buf = (char *)malloc(BUF_LEN);

	while (1) {
		// 记录当前的时间
		time(&rawtime);
		timeinfo = localtime(&rawtime);
		memset(buf, 0, BUF_LEN);
		sprintf(buf, "\n[%02d:%02d:%02d] \n",
				timeinfo->tm_hour, 
				timeinfo->tm_min, 
				timeinfo->tm_sec);
		log_msg(buf);

		// 此for循环用于获取监控进程的资源占用情况
		for (i = 0; i < count; i++) {
			memset(buf, 0, BUF_LEN);
			sprintf(buf, "[%s] \n", ProcessList[i]);
			log_msg(buf);

			for (k = 0; k < TRACE_ITEM_NUM; k++) {
				memset(buf, 0, BUF_LEN);
				// 获取进程ID号: 执行系统命令,然后读取输出结果。
				sprintf(buf, 
				    "ps -aux | grep %s | grep -v grep | awk '{print $2}'", 
				    ProcessList[i]);
				FILE *fp = popen(buf, "r");
				if (NULL == fp) {
					printf("popen failed! \n");
					continue;
				}

				char line[128] = { 0 };
				fgets(line, 128, fp);
				int len = strlen(line);
				if (*(line + len - 1) == '\n')
					*(line + len - 1) = 0;
				pclose(fp); 

				// 根据进程ID号,获取该进程的堆栈信息。
				memset(buf, 0, BUF_LEN);
				sprintf(buf, 
						"cat /proc/%s/status | grep %s | grep -v grep", 
						line, TraceItem[k]);
				
				fp = popen(buf, "r");
				if (NULL == fp) {
					printf("popen failed! \n");
					continue;
				}
				fgets(line, 128, fp);
				pclose(fp);
				log_msg(line);   // 记录到日志
			}
		}

		// 获取系统的空闲资源信息
		memset(buf, 0, BUF_LEN);
		sprintf(buf, "free | grep Mem: | grep -v grep");
		FILE *fp = popen(buf, "r");
		if (NULL == fp) {
			printf("popen failed! \n");
			continue;
		}

		char line[128] = { 0 };
		fgets(line, 128, fp);
		pclose(fp);
		log_msg(line);

		sleep(5);    // 间隔一段时间
	}

	// 释放 malloc 分配的堆空间
	free(buf);

	for (i = 0; i < PROCESS_MAX; i++) {
		if (ProcessList[i])
			free(ProcessList[i]);
	}

	return 0;
}

3. Printout

    The function of this tool is actually very simple, that is, calling system commands to monitor the system resources occupied by the process.

 

    Specifically, it continuously outputs the contents of /proc/[pid]/status. There are 4 key indicators in this file, which are briefly listed here, and you can search for their specific meanings.

    VmSize(KB): The virtual memory size used by the process.

    VmRSS(KB): The part of the process that resides in physical memory and is not swapped to the hard disk.

    VmStk(KB): The size of the stack used by the process.

    VmData(KB): The size of the process data segment.

 

[Why write this gadget]

 I wrote about a gateway product for the Internet of Things before, which includes 3 large modules, and they are handled by different people. The worst thing is: one of these three people is in Japan, one is in Taiwan, and the other is us.

 

    During the integration test, it was found that there was a continuous decrease in system resources, and no regularity could be found. Because there are many interactions between processes, memory leaks may only occur when certain specific execution logic is triggered.

 

    In order to find out the culprit, I wrote this small tool. After about 2 days of execution, the source of the problem was quickly located.

 

[Problems you may encounter]

1. System instructions

    Several system commands are used in the program: proc, grep, awk, free.

    The output format of these instructions in different embedded systems may be different. If there is a problem with the output of running this tool directly, then the instruction parsing part of the code needs to be adjusted.

 

2. How to adjust

    For example: use this instruction in the code to get the process ID according to the process name: ps -aux | grep %s | grep -v grep | awk'{print $2}'

   For the ps command, you may not need the -aux attribute in your system.

    For the awk command, the built-in extracted in your system may be'{print $1}'.

    Real knowledge from practice!

 

【END】

1. This is an original article, please respect the copyright. If you need to reprint, please keep the entire content and indicate the source. If it is convenient, please contact me to confirm.

2. If there are errors in the article, or if you want to communicate or discuss related content, please feel free to contact me.

3. Email: [email protected]

4. Public account: IOT Internet of Things Town 

 

Guess you like

Origin blog.csdn.net/u012296253/article/details/106781754