栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

如何在运行时查看我的程序在C中的内存布局?

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

如何在运行时查看我的程序在C中的内存布局?

在Linux中,对于进程PID,请查看

/proc/PID/maps
/proc/PID/smaps
伪文件。(该过程本身可以使用
/proc/self/maps
/proc/self/smaps
。)

它们的内容记录在man 5 proc中。


这是一个如何将内容读入地址范围结构的链接列表的示例。

mem-stats.h

#ifndef   MEM_STATS_H#define   MEM_STATS_H#include <stdlib.h>#include <sys/types.h>#define PERMS_READ    1U#define PERMS_WRITE   2U#define PERMS_EXEC    4U#define PERMS_SHARED  8U#define PERMS_PRIVATE16Utypedef struct address_range address_range;struct address_range {    struct address_range    *next;    void         *start;    size_t        length;    unsigned long offset;    dev_t         device;    ino_t         inode;    unsigned char perms;    char          name[];};address_range *mem_stats(pid_t);void free_mem_stats(address_range *);#endif 

mem-stats.c

#define _POSIX_C_SOURCE 200809L#define _BSD_SOURCE#include <stdlib.h>#include <sys/types.h>#include <string.h>#include <stdio.h>#include <errno.h>#include "mem-stats.h"void free_mem_stats(address_range *list){    while (list) {        address_range *curr = list;        list = list->next;        curr->next = NULL;        curr->length = 0;        curr->perms = 0U;        curr->name[0] = '';        free(curr);    }}address_range *mem_stats(pid_t pid){    address_range *list = NULL;    char          *line = NULL;    size_t         size = 0;    FILE          *maps;    if (pid > 0) {        char namebuf[128];        int  namelen;        namelen = snprintf(namebuf, sizeof namebuf, "/proc/%ld/maps", (long)pid);        if (namelen < 12) { errno = EINVAL; return NULL;        }        maps = fopen(namebuf, "r");    } else        maps = fopen("/proc/self/maps", "r");    if (!maps)        return NULL;    while (getline(&line, &size, maps) > 0) {        address_range *curr;        charperms[8];        unsigned int   devmajor, devminor;        unsigned long  addr_start, addr_end, offset, inode;        int name_start = 0;        int name_end = 0;        if (sscanf(line, "%lx-%lx %7s %lx %u:%u %lu %n%*[^n]%n",   &addr_start, &addr_end, perms, &offset,   &devmajor, &devminor, &inode,   &name_start, &name_end) < 7) { fclose(maps); free(line); free_mem_stats(list); errno = EIO; return NULL;        }        if (name_end <= name_start) name_start = name_end = 0;        curr = malloc(sizeof (address_range) + (size_t)(name_end - name_start) + 1);        if (!curr) { fclose(maps); free(line); free_mem_stats(list); errno = ENOMEM; return NULL;        }        if (name_end > name_start) memcpy(curr->name, line + name_start, name_end - name_start);        curr->name[name_end - name_start] = '';        curr->start = (void *)addr_start;        curr->length = addr_end - addr_start;        curr->offset = offset;        curr->device = makedev(devmajor, devminor);        curr->inode = (ino_t)inode;        curr->perms = 0U;        if (strchr(perms, 'r')) curr->perms |= PERMS_READ;        if (strchr(perms, 'w')) curr->perms |= PERMS_WRITE;        if (strchr(perms, 'x')) curr->perms |= PERMS_EXEC;        if (strchr(perms, 's')) curr->perms |= PERMS_SHARED;        if (strchr(perms, 'p')) curr->perms |= PERMS_PRIVATE;        curr->next = list;        list = curr;    }    free(line);    if (!feof(maps) || ferror(maps)) {        fclose(maps);        free_mem_stats(list);        errno = EIO;        return NULL;    }    if (fclose(maps)) {        free_mem_stats(list);        errno = EIO;        return NULL;    }    errno = 0;    return list;}

使用以上示例的示例程序 example.c

#include <stdlib.h>#include <unistd.h>#include <string.h>#include <stdio.h>#include <errno.h>#include "mem-stats.h"int main(int argc, char *argv[]){    int  arg, pid;    char dummy;    if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {        fprintf(stderr, "n");        fprintf(stderr, "Usage: %s [ -h | --help ]n", argv[0]);        fprintf(stderr, "       %s PIDn", argv[0]);        fprintf(stderr, "n");        fprintf(stderr, "You can use PID 0 as an alias for the command itself.n");        fprintf(stderr, "n");        return EXIT_SUCCESS;    }    for (arg = 1; arg < argc; arg++)        if (sscanf(argv[arg], " %i %c", &pid, &dummy) == 1) { address_range *list, *curr; if (!pid)     pid = getpid(); list = mem_stats((pid_t)pid); if (!list) {     fprintf(stderr, "Cannot obtain memory usage of process %d: %s.n", pid, strerror(errno));     return EXIT_FAILURE; } printf("Process %d:n", pid); for (curr = list; curr != NULL; curr = curr->next)     printf("t%p .. %p: %sn", curr->start, (void *)((char *)curr->start + curr->length), curr->name); printf("n"); fflush(stdout); free_mem_stats(list);        } else { fprintf(stderr, "%s: Invalid PID.n", argv[arg]); return EXIT_FAILURE;        }    return EXIT_SUCCESS;}

和一个使构建起来很简单的 Makefile

CC      := gccCFLAGS  := -Wall -Wextra -O2 -fomit-frame-pointerLDFLAGS := PROGS   := example.PHONY: all cleanall: clean $(PROGS)clean:    rm -f *.o $(PROGS)%.o: %.c    $(CC) $(CFLAGS) -c $^example: mem-stats.o example.o    $(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@

请注意,上面的Makefile中的三行缩进行 必须 使用制表符,而不是空格。似乎这里的编辑器将制表符转换为空格,因此您需要修复此问题,例如通过使用

sed -e 's|^  *|t|' -i Makefile

如果您不解决缩进问题,而在Makefile中使用空格,则会看到类似于的错误消息

*** missing separator. Stop

某些编辑器会自动将

tab
按键转换为多个空格,因此您可能需要研究使用的任何编辑器的编辑器设置。通常,编辑者会完整保留粘贴的制表符,因此您始终可以尝试从另一个程序粘贴制表符。

要编译并运行,请保存以上文件并运行:

make./example 0

打印示例程序本身使用的内存范围。例如,如果您想查看PulseAudio守护程序使用的内存范围,请运行:

./example $(ps -o pid= -C pulseaudio)

请注意,适用标准访问限制。普通用户只能看到以该用户身份运行的进程的内存范围。否则,您需要超级用户权限(

sudo
或类似权限)。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/409003.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号