Listo para usar: comparte una pequeña herramienta para comprobar si hay fugas de memoria

【Función descriptiva】

        Durante el desarrollo de aplicaciones de sistemas integrados, la pérdida de memoria es un problema muy serio y doloroso. Por supuesto, hay muchas herramientas y software profesionales para verificar si hay fugas de memoria, yo uso memwatch y valgrind más.

        Estas herramientas se utilizan principalmente para comprobar las pérdidas de memoria durante el proceso de desarrollo. Sin embargo, si se han desarrollado todos los programas y se inicia la prueba de integración, todavía se encuentra que hay una disminución continua en los recursos del sistema, entonces ¿cómo lidiar con eso?

        Las pequeñas herramientas proporcionadas aquí se utilizan para hacer frente a esta situación: puede supervisar los recursos del sistema utilizados por aquellos procesos que sospecha que pueden tener pérdidas de memoria.

        Especialmente cuando un sistema es desarrollado por varias personas y está compuesto por múltiples procesos, si hay una fuga de recursos, ¿quién cree que debería sospecharse primero? ¿A quién se le debe pedir que verifique primero si hay un problema con su programa? Las disputas ocurren a menudo, y el distanciamiento entre los pequeños amigos ha plantado las semillas en el subconsciente.

        En este punto, ¡la salida de datos del programa de monitoreo es más útil!

 

 

【entorno de prueba】

1. sistema x86

    Lo probé en Ubuntu 16.04, usando el compilador gcc que viene con el sistema.

2. Sistema integrado

    Simplemente cambie el compilador al compilador cruzado correspondiente.

 

【Descarga de código】

1. SkyDrive

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

    passwd: uqbh

 

2. Descripción del archivo

    El código central es solo un archivo: memory_trace.c, y los otros dos son scripts de compilación.

/**
 * @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. Impresión

    La función de esta herramienta es realmente muy simple, es decir, llamar a los comandos del sistema para monitorear los recursos del sistema ocupados por el proceso.

 

    Específicamente, genera continuamente: el contenido de / proc / [pid] / status. Hay 4 indicadores clave en este archivo, que se enumeran brevemente aquí, y puede buscar sus significados específicos.

    VmSize (KB): el tamaño de la memoria virtual que utiliza el proceso.

    VmRSS (KB): la parte del proceso que reside en la memoria física y no se intercambia en el disco duro.

    VmStk (KB): el tamaño de la pila que utiliza el proceso.

    VmData (KB): el tamaño del segmento de datos de proceso.

 

[Por qué escribir este gadget]

 Antes escribí sobre un producto de puerta de enlace para Internet de las cosas, que incluye 3 módulos grandes y los manejan diferentes personas. Lo peor es que una de estas tres personas está en Japón, otra en Taiwán y la otra nosotros.

 

    Durante la prueba de integración, se encontró que había una disminución continua en los recursos del sistema y no se encontró regularidad. Debido a que existen muchas interacciones entre los procesos, las pérdidas de memoria solo pueden ocurrir cuando se activa cierta lógica de ejecución específica.

 

    Para descubrir al culpable, escribí esta pequeña herramienta. Después de aproximadamente 2 días de ejecución, se localizó rápidamente la fuente del problema.

 

[Problemas que puede encontrar]

1. Instrucciones del sistema

    En el programa se utilizan varios comandos del sistema: proc, grep, awk, free.

    El formato de salida de estas instrucciones en diferentes sistemas embebidos puede ser diferente. Si hay un problema con la salida de ejecutar esta herramienta directamente, entonces la parte del código que analiza la instrucción necesita ser ajustada.

 

2. Cómo ajustar

    Por ejemplo: use esta instrucción en el código para obtener el ID del proceso de acuerdo con el nombre del proceso: ps -aux | grep% s | grep -v grep | awk '{print $ 2}'

   Para el comando ps, es posible que no necesite el atributo -aux en su sistema.

    Para el comando awk, el extraído incorporado en su sistema puede ser '{print $ 1}'.

    ¡Conocimiento real de la práctica!

 

【FINAL】

1. Este es un artículo original, respete los derechos de autor. Si necesita reimprimir, conserve todo el contenido e indique la fuente. Si es conveniente, contácteme para confirmar.

2. Si hay errores en el artículo, o si desea comunicarse o discutir contenido relacionado, no dude en ponerse en contacto conmigo.

3. Correo electrónico: [email protected]

4. Cuenta pública: IOT Internet of Things Town 

 

Supongo que te gusta

Origin blog.csdn.net/u012296253/article/details/106781754
Recomendado
Clasificación