查看maps

程序运行后输出进程号、结构体地址必要信息,然后进入循环,如此让进程不立即退出,方便调试

8f2fd0060844646caa3cae7abb69b5e5.png

执行cat /proc/6568/maps查看其内存分布情况

119001975f1dade41608bf5ddcf6ff6c.png

任务启动时看到为结构体申请的内存的地址是0x8108008,结合cat /proc/6568/maps,正好在堆内存上

ed8af95fe777b11ac4bdc43e93f35283.png

使用GDB调试

gdb开启调试器,然后attach 6568附到该进程上,准备进行调试

a4852a64687785108e3e40a7815f4ea1.png

因为上面输出结构体是52字节,地址是0x8108008,所以我们用x命令查看从0x8108008开始的52字节,x/52cb 0x8108008

d47b0152e151ca359f29ec6af4c330a5.png

简单验证其中的字符部分,确实有”xumenger”和”xuzhou”

仔细分析也存在结构体对齐的问题,因为这个点比较熟悉了,所以不再赘述

Linux下的堆内存

我们修改一下程序,将其中的如下代码删除

Person *p;

p = malloc(sizeof(Person));

printf("address=%p, size=%d\n", p, sizeof(Person));

p->age = 10;

p->weight = 100.10;

strcpy(p->name, "xumenger");

strcpy(p->address, "xuzhou");

也就是不申请堆内存,编译运行程序

c37000c7ed8944fd6287db2cb43205f9.png

然后再去cat /proc/6595/maps查看进程内存布局

657b440c7a5c478d2341f5295a64780e.png

这次没有堆内存了

所以上面测试中遇到的第一次申请的内存地址,正好等于/proc/pid/maps看到的堆内存地址,并不是巧合!

最后附上测试源码

#include

#include

#include

#include

#include

#include

typedef struct{

int age;

double weight;

char name[20];

char address[20];

}Person;

int isClose = 0;

void Stop(int signo);

int main()

{

printf("pid=%d\n", getpid());

//注册信号

signal(SIGINT, Stop);

Person *p;

p = malloc(sizeof(Person));

printf("address=%p, size=%d\n", p, sizeof(Person));

p->age = 10;

p->weight = 100.10;

strcpy(p->name, "xumenger");

strcpy(p->address, "xuzhou");

//循环保证进程不立即退出,方便GDB attach到上面进行调试

while(0 == isClose){

usleep(1000);

}

printf("stop\n");

return 0;

}

//使用信号通知进程退出

void Stop(int signo)

{

isClose = 1;

}

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐