Linux进程信息及内存分布简介

一、linux进程信息

本文以thread进程为例,简单创建两个线程。

1、获取进程状态cat/proc/<pid>/status(海思平台和ST平台差不多)

Name:  thread

State: S (sleeping)

Tgid:  1199

Pid:   1199

PPid:  1195

TracerPid:      0

Uid:   0       0       0      0

Gid:   0       0       0      0

FDSize: 32

Groups: 0

VmPeak:   13156 kB

VmSize:   13156 kB

VmLck:         0 kB

VmHWM:      256 kB

VmRSS:      256 kB

VmData:   12448 kB

VmStk:      160 kB

VmExe:      544 kB

VmLib:         0 kB

VmPTE:        12 kB

VmSwap:        0 kB

Threads:        3

SigQ:  0/1223

SigPnd: 0000000000000000

ShdPnd: 0000000000000000

SigBlk: 0000000000000000

SigIgn: 0000000000000004

SigCgt: 0000000180000000

CapInh: 0000000000000000

CapPrm: ffffffffffffffff

CapEff: ffffffffffffffff

CapBnd: ffffffffffffffff

Cpus_allowed:   1

Cpus_allowed_list:      0

voluntary_ctxt_switches:        5

Name: //进程名字

State: //任务状态, 运行/睡眠/僵死/

Tgid:  //线程组号

Pid:  //任务ID

PPid: //父进程ID

TracerPid: //接收跟踪该进程信号的进程ID号

FDSize: //文件描述符最大个数

Groups: //启动该进程用户所属的组ID

VmPeak:         //进程地址空间的大小,进程运行过程中占用内存的峰值,代表占用的最大内存空间

VmSize:        //虚拟地址空间大小(total_vm进程地址空间大小 -reserved_vm进程在预留的内存间物理页)

VmLck:            //已经锁定的物理内存大小(loack_vm)

VmHWM:             //应用程序使用物理内存大小峰值

VmRSS:        //应用程序正在使用的物理内存大小

VmData:      //程序数据段的大小(所占虚拟内存大小),存放了初始化数据(total_vm - shared_vm - stack_vm)

VmStk:              //任务用户堆栈大小(stack_vm)

VmExe:      //程序拥有的可执行虚拟内存大小,代码段,不包括任务使用的库(end_code_start_code)

VmLib:            //被映像到任务的虚拟内存空间的库大小(exec_lib)

VmPTE:            //该进程页表大小

Threads:           //线程个数

SigQ:  0/1935                                             //待处理信号个数

SigPnd: 0000000000000000    //屏蔽位,存储了该线程的待处理信号

ShdPnd: 0000000000000000   //屏蔽位,存储了该线程组的待处理信号

SigBlk: 0000000000000000     //存放被阻塞的信号

SigIgn: 0000000000000001     //存放被忽略信号

SigCgt: 00000001e0001cfe      //存放被俘获到的信号

CapInh: 0000000000000000   //能被当前进程执行的程序的继承能力

CapPrm: ffffffffffffffff        //进程能够使用的能力

CapEff: ffffffffffffffff //进程有效能力

CapBnd: ffffffffffffffff

Cpus_allowed:   3

Cpus_allowed_list:      0-1

voluntary_ctxt_switches:        1125

nonvoluntary_ctxt_switches:     301

2、获取进程内存空间映射cat/proc/<pid>/maps(海思平台)

反应进程占用的内存区域,每行数据意思:

开始——结束         访问权限         偏移         主设备号:次设备号        i节点       文件

00008000-00090000r-xp 00000000 00:0f 1014855   /home/thread

00090000-00091000rw-p 00088000 00:0f 1014855   /home/thread

00091000-00095000 rw-p00000000 00:00 0

0137d000-0139f000rw-p 00000000 00:00 0          [heap]

2ab52000-2ab53000rw-p 00000000 00:00 0

2ab71000-2ab72000 ---p00000000 00:00 0

2ab72000-2b171000 rw-p00000000 00:00 0

2b218000-2b219000---p 00000000 00:00 0

2b219000-2b818000rw-p 00000000 00:00 0

7e973000-7e99a000 rw-p 00000000 00:00 0          [stack]

ffff0000-ffff1000 r-xp 00000000 00:000          [vectors]

3、获取进程内存空间映射cat/proc/<pid>/maps(ST平台)

00008000-00078000r-xp 00000000 00:13 1047568   /home/n7/thread

0007f000-00081000rw-p 0006f000 00:13 1047568   /home/n7/thread

00081000-00084000rw-p 00000000 00:00 0

01499000-014bb000rw-p 00000000 00:00 0          [heap]

75fe4000-75fe5000 ---p00000000 00:00 0

75fe5000-767e4000 rw-p00000000 00:00 0          [stack:437]

767e4000-767e5000---p 00000000 00:00 0

767e5000-76fe5000rw-p 00000000 00:00 0         [stack:436]

7e9f7000-7ea1e000 rw-p 00000000 00:00 0          [stack]

ffff0000-ffff1000 r-xp 00000000 00:000          [vectors]

4、进程maps解析

从maps可以得到进程的一个内存布局图,不同颜色代表程序不同段映射:

(1)代码段

00008000-00090000r-xp 00000000 00:0f 1014855   /home/thread

(2)数据和BSS段

00090000-00091000rw-p 00088000 00:0f 1014855   /home/thread

00091000-00095000rw-p 00000000 00:00 0

数据和bss段与代码段基本都是紧挨着的。

(3)堆heap

01499000-014bb000rw-p 00000000 00:00 0          [heap]

向上增长

(4)mmap区域

thread进程主要是创建了两个线程,每个线程的堆栈大小为6M。

2ab71000-2ab72000 ---p00000000 00:00 0 //4K

2ab72000-2b171000 rw-p00000000 00:00 0         //6M

2b218000-2b219000---p 00000000 00:00 0 //4K

2b219000-2b818000rw-p 00000000 00:00 0         //6M

A.     海思与ST平台对比发现创建线程时mmap增长方向刚好相反,见第四节。

B.     线程通过mmap方式映射,为啥每个线程都多一个4K,见第三节。

(5)stack区域

7e973000-7e99a000 rw-p 00000000 00:00 0          [stack]

位于地址高位,向下增长。

二、进程镜像信息与maps关系

使用objdump工具可以查找thread二进制文件的地址和符号信息,和maps内容对比发现基本是一致的。

1、代码段

arm-hisiv200-linux-objdump -t thread | grep"\.text"得到如下信息:

……

0004e140 g     F .text 00000008__wmemcpy

0001b810 g     F .text 00000008_IO_iter_next

0006e34c g     F .text 00000cb0_dl_close_worker

00022cd0 g     F .text 00000344__valloc

0000929c g     F .text 00000198__pthread_init_static_tls

00055624 g     F .text 00000014__geteuid

00026f68 g     F .text  0000013c_wordcopy_bwd_aligned

…….

从第一列地址看,代码段的地址范围与上面的maps获取到的地址范围是一致的。

2、数据段:

arm-hisiv200-linux-objdump -t thread | grep"\.data"得到如下信息:

00090024 l    d .data.rel.ro       00000000.data.rel.ro

000900c8 l    d .data         00000000 .data

000900d0 l     O .data 00000008stack_used

……………..

0009056c g     O .data         00000004_dl_make_stack_executable_hook

00090568 g     O .data        00000004_dl_correct_cache_id

00090538 w    O .data      00000004 __memalign_hook

00090240 g     O .data        000000a0_IO_2_1_stderr_

00090550 g     O .data        00000004__progname_full

数据地址与maps一致

3、bss段

arm-hisiv200-linux-objdump -t thread | grep"\.bss"得到如下信息

000907d0 l    d .bss  00000000 .bss

000907d0 l     O .bss   00000001completed.5624

000907d4 l     O .bss   00000004in_flight_stack

000907d8 l     O .bss   00000004stack_cache_actsize

000907e4 l     O .bss   00000004stack_cache_lock

000907e8 l     O .bss   00000008__nptl_threads_events

000907f0 l     O .bss    00000004__nptl_last_event

000907f8 l     O .bss    00000001__nptl_initial_report_events

00092800 l     O .bss   00000208static_slotinfo

00092a08 l     O .bss   00000200static_dtv

…..

000941d4 g     O .bss 00000004_dl_osversion

000941d8 g     O .bss 00000004_dl_inhibit_rpath

000941dc g     O .bss  00000004_dl_pagesize

000941e0 g     O .bss 0000004c_dl_ns

地址同maps对比发现,最开始的地方使用了数据段的地址空间。

三、strace跟踪进程

通过strace工具跟踪thread创建两个线程的过程:

/home/n5x/strace home/n5x/thread 2:

execve("home/n5x/thread",["home/n5x/thread", "2"], [/* 8 vars */]) = 0

uname({sys="Linux",node="host", ...})  = 0

brk(0)                                  = 0x163e000

brk(0x163ed04)                          = 0x163ed04

set_tls(0x163e4c0, 0x90014, 0xffffffe0, 0x14,0x92800) = 0

set_tid_address(0x163e068)              = 1199

set_robust_list(0x163e070, 0xc)         = 0

futex(0x7e85cd14, FUTEX_WAKE_PRIVATE, 1) =0

futex(0x7e85cd14,FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, 1, NULL, 163e08c) = -1 EAGAIN(Resource temporarily unavailable)

rt_sigaction(SIGRTMIN, {0xd870, [],SA_SIGINFO|0x4000000}, NULL, 8) = 0

rt_sigaction(SIGRT_1, {0xd714, [],SA_RESTART|SA_SIGINFO|0x4000000}, NULL, 8) = 0

rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1],NULL, 8) = 0

getrlimit(RLIMIT_STACK,{rlim_cur=6144*1024, rlim_max=6144*1024}) = 0

brk(0x165fd04)                          = 0x165fd04

brk(0x1660000)                          = 0x1660000

fstat64(1, {st_mode=S_IFCHR|0600,st_rdev=makedev(204, 64), ...}) = 0

ioctl(1, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICEor TCGETS, {B115200 opost isig icanon echo ...}) = 0

mmap2(NULL, 4096, PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2ab02000

write(1, "stacksize 6291456\n",18stacksize 6291456

)    = 18

mmap2(NULL, 6291456, PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2ab5a000

mprotect(0x2ab5a000, 4096, PROT_NONE)   = 0

clone(child_stack=0x2b158e38,flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID,parent_tidptr=0x2b159368, tls=0x2b1597c0, child_tidptr=0x2b159368) = 1200

write(1, "stacksize 6291456\n",18stacksize 6291456

)    = 18

mmap2(NULL, 6291456,PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b166000

mprotect(0x2b166000, 4096, PROT_NONE)   = 0

clone(child_stack=0x2b764e38,flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID,parent_tidptr=0x2b765368, tls=0x2b7657c0, child_tidptr=0x2b765368) = 1201

write(1, "i=2\n", 4i=2

)                    = 4

write(1, "wait a moment, \n",16wait a moment,

)      = 16

rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) =0

rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [],0}, 8) = 0

上面的蓝色和紫色分别创建了一个线程,其中有一个mprotect函数创建了4KB与mmap对应的内存保护区,该区域用户无法操作,如果意外操作就会出错。这就是为什么在maps中每个线程会有一个4KB的原因。

四、不同内核进程内存布局

对比海思(3.0.8)和ST(3.4.7)平台,maps中线程mmap增长方向是相反的。说明不同的内核版本采用不同的内存布局,对于早期的内核采用3.0.8的经典内存布局,最新的都是3.4.7的灵活内存布局。

1、经典内存布局

经典布局mmap的增长方向:向上增长,如图:

对于经典模式,heap和mmap都是向上增长的,于是在内核中就为heap保留了一定空间:heap ~mmap起始地址。

mmap起始地址计算方法:

在内核代码/arch/arm/mm/mmap.c

start_addr = TASK_UNMAPPED_BASE

#define TASK_UNMAPPED_BASE (UL(CONFIG_PAGE_OFFSET) / 3)

CONFIG_PAGE_OFFSET= 0xc0000000(对于2G的就是0x80000000)

因此,在这种情况下,mmap可用区域并不是3G,而是2*( CONFIG_PAGE_OFFSET) /3。

2、灵活内存布局

灵活内存布局的增长方向:向下增长,如图:

从图中可以看出,栈至顶向下扩展,并且栈是有界的。对至底向上增长,mmap映射区域至顶向下扩展,直至耗尽虚拟地址空间的剩余区域。

当栈中压入数据超出其容量就会耗尽栈所对应的内存区域,这将触发一个页故障(page fault),并被linux的expand_stack()处理,调用acct_stack_growth来检查是否有合适的地方用于栈的增长。如果栈的大小低于RLIMIT_STACK,那么一般情况下栈会加长。

另外,可以看出栈和mmap映射区域不是从一个固定的地址开始,而是程序启动时有一个随机的偏移,这样使得使用缓冲区溢出攻击的方法更加困难。如果想使地址固定,设置

/proc/sys/kernel/randomize_va_space为0。

也可以将灵活内存布局设置为经典内存布局,设置变量/proc/sys/vm /legacy_va_layout为1。

五、其他补充

嵌入式Linux进程信息及内存布局相关推荐

  1. 嵌入式linux启动信息完全注释

    嵌入式linux启动信息完全注释 from:http://www.embedlinux.cn/ShowPost.asp?ThreadID=377 摘要 我们在这里讨论的是对嵌入式linux系统的启动过 ...

  2. linux进程中的内存分布

    很多小伙伴在调试C代码的时候非常痛苦,C语言不像java那样可以给你指出具体的错误地方和错误原因,C语音因为指针的特殊性和C语言版本的兼容性的需要,很难直接定位到错误的地方.特别是各种段错误.溢出等. ...

  3. linux用户空间内存分布,了解linux 64位地址空间内存布局

    主要搞清楚下列问题: 1.X86-64 页式管理有哪些改变? 2.Linux是怎样支持64bit地址管理? 3.64bit 内存布局是怎么样的? 1. X86-64 页式管理 查看<64-ia- ...

  4. 【操作系统实验】Linux进程通信—共享内存通信、管道通信

    Linux进程通信-共享内存通信.管道通信 一.实验目的: 二.实验题目: 1. 试设计程序利用共享内存完成如下进程通信 1.shmget函数 2.shmat函数 3.shmdt函数 4.shmctl ...

  5. [内存管理]linux X86_64处理器的内存布局图(转自:http://blog.csdn.net/younger_china/article/details/16829687)

    Linux X86 64位内存布局图

  6. [内存管理]linux X86_64处理器的内存布局图

    linux X86 64位内存布局图

  7. linux 进程装入 物理内存 页表,linux内存管理解析----linux物理,线性内存布局及页表的初始化...

    主要议题: 1分页,分段模式及实模式 2Linux分页 3linux内存线性地址空间布局及物理内存空间布局 4linux页表初始化及代码解析 1.1.1内存寻址和保护模式 在X86平台上,内存控制单元 ...

  8. 查看 linux 硬件信息:内存、分区、系统、环境变量、防火墙、路由、端口监听、进程、CPU...

    前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家.点击跳转到教程. 一.linux CPU大小: 其实应该通过Physical Processor ID来区分单核和双核 ...

  9. Linux 进程资源分配,linux 进程管理和内存分配

    1.进程相关概念 进程:正在运行中的程序 内核功用:进程管理.文件系统.网络功能.内存管理.驱动程序.安全功能等 Process:运行中的程序的一个副本,是被载入内存的一个指令集合 进程 ID(Pro ...

  10. 32位linux进程线程在内存中的样子

    1.线程诞生史 1.1 线程诞生的原因 早期是没有线程概念的,只有进程的概念,操作系统以进程为调度单位.--可以这么来理解:早期进程相当于现在的单线程的进程(只有一个线程的进程,创建进程时,里面有一个 ...

最新文章

  1. java匿名对象赋初值_不想进BAT的Java程序员不是好程序员,BAT后端Java岗面试真题分享
  2. 大型网站系统架构实践(五)深入探讨web应用高可用方案
  3. IOS中将对象属性列表归档成一个plist文件中
  4. 利用Java进行MySql数据库的导入和导出
  5. Swift 2.3- 3.0
  6. pycharm 操作的一些设置,记录下
  7. c语言4x4按键计算器代码,4X4按键实现计算器功能.doc
  8. python中协程与函数的区别_python协程和异步IO
  9. VB 使用SendMessage枚举文件与目录
  10. 今天小小的总结一下最近的小程序中的问题
  11. matlab 支撑集,基于OMP算法的快速压缩感知图像重构
  12. docker 设置阿里云加速器
  13. 信创操作系统--统信UOS桌面版(多媒体软件:图像查看、处理,音频播放、录音机)
  14. 深度评测 极米z6x和z6哪个好 极米z6和z6x区别
  15. 网站防御DDoS的方案--高防节点(高防IP)
  16. c语言 dct变换,DCT, IDCT变换--C语言实现
  17. Java毕业设计_基于javaEE的论坛的设计和实现
  18. iOS用户行为追踪——无侵入埋点
  19. SYN攻击原理以及防范技术
  20. 机器学习分类算法之随机森林(集成学习算法)

热门文章

  1. Codeforces 160
  2. javascript复习总结
  3. 为什么要使用class.forname在DriverManager.getConnection之前
  4. asp.net core 返回的Server Kestrel是什么
  5. 链接数据库 远程事务的处理方式
  6. TableView载入WebView的一些小技巧 By 徐
  7. .net开发微信公众号(3)-接收微信推送的消息
  8. 合并查找到的文件,至新的文件中
  9. C++的C4305和C4800的编译警告
  10. Android程序创意过滤与失败经验谈