免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3862 | 回复: 6
打印 上一主题 下一主题

问一个关于Linux上内存的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-09-19 16:04 |只看该作者 |倒序浏览
在Linux上,程序的在编译时确定了代码段、数据段等除堆和栈部分的大小,堆和栈是在程序运行时确定的,但是不管怎样,都会给他们分配一个起始地址,栈是从高地址向低地址扩展,而堆是从低地址向高地址扩展的。那我有几个问题:
1. 是系统的哪一部分给他们分配了地址,各自分配多少呢,依据是什么?
2. 一个程序的虚拟内存区的地址和另外一个虚拟内存区的地址是独立的,还是统一的呢?如果是独立的,在进程切换时,是系统的哪一部分负责管理这么多种地址?而如果是统一的,在系统分配了确定的堆和栈的起始地址后,如果需要的空间超过了现在的容量,但是还远远没有达到32系统最大的4G大小时,系统又是如何处理的呢?

盼望高人指点!!any reply is appreciated!

论坛徽章:
0
2 [报告]
发表于 2006-09-19 23:01 |只看该作者
去随便找一本操作系统原理的书看完再来提问题。

论坛徽章:
0
3 [报告]
发表于 2006-09-20 09:42 |只看该作者

回复 2楼 YaoFei 的帖子

你可以回答的很好吗?你确定你可以回答吗?
你的这种回复似乎不是很友好啊

论坛徽章:
0
4 [报告]
发表于 2006-09-20 20:06 |只看该作者
这个问题涉及到的东西必较多,有些我记得不是很清楚,有问题请大家指出,多谢。

第一个问题:

在Linux系统中,堆和栈的地址和大小是在内核中分配的。
当用户空间的某个可执行程序被execve()系统调用加载的时候,在内核中最终会调用到load_×_binary(),如果文件是ELF格式,调用load_elf_binary(). 众所周知,Linux的用户空间任务再运行中能获得的最大地址是0xbfffffff,一个程序运行后,其内存图为:
|----------|
| env list |
|----------|
| argv list|
|-----| stack_top
| stack  | |
|        v |
|          |
|          |
|----------|stack_base
|          |
|          |
|          |
|          |
|----------| brk
|  heap  A |
|        | |
|----------| brk_start
|   bss    |
|----------|
|   data   |
|----------|
|   text   |
|----------|

stack起始地址stack_top,Linux内核是从0xc0000000 - 最多可能的参数数*页表大小- ?,所以得到的地址大概是0xbfcxxxx,大小根据每个任务的最大堆栈值确定,这个值存放在task->signal->rlim[RLIMIT_STACK].rlim_max中,可以通过setrlimit()系统调用修改,但即使你设置成无限制,内核最多预留不超过分配操作1G的stack.
heap的其实地址从bss开始算起,bss在elf格式中的flags WA,所以,内核首先会分配bss, 才能确定brk_start,所以brk_start和程序的startpointe entry, text,data,bss的大小都有关系,这些信息在elf头中都可以获取。heap的大小:在默认情况下,刚加载的程序,heap很小,当程序开始运行时,会调用malloc分配heap中的内存,这时,glibc库负责调用brk()或者mmap()从内核中分配内存,这些系统调用最终都会调用do_brk()调整brk地址,即向stack的方向增加。

第二个问题:
不知道你说得"另外一个虚拟内存区"是不是另外一个任务的虚拟内存区,如果是,内核是这样解决的:
所有的用户空间程序占用的虚拟内存空间是重叠的,某个任务占用的虚拟内存是通过页表来映射到物理内存的,页表的起始地址存放在每个任务的task->mm->pgd_t中。当任务发生切换时,这个页表首地址被通过load_cr3()变换成新任务的页表。所以,这些地址的管理是通过task自身的mm管理机制来完成的。因为每个任务有自己独立的页表,所以不存在你后面提到的超过容量的问题。

有问题欢迎继续讨论。

论坛徽章:
0
5 [报告]
发表于 2006-09-22 09:16 |只看该作者

回复 4楼 xiaozhaoz 的帖子

基本都明白了,第2个问题是没有问题的了,每个进程的虚拟地址是通过进程切换来映射不同的物理地址的。第一个问题,我简单描述一下,看看我说的对不对。“Linux的用户空间任务再运行中能获得的最大地址是0xbfffffff”,也就是3G的内存,那么假定env list 和argv list|总共占了1K的空间,bss、text和data总共占了3K的空间,那么heap和stack总共可用的空间就是『3G-1k-3K』。由于在不指定定stack大小,而且系统设置为没有限制的情况下,stack最多可以用1G,剩下的部分都可以给heap用了,楼上的牛牛看我说的对吗?

论坛徽章:
0
6 [报告]
发表于 2006-09-22 11:29 |只看该作者
如果只说理解大概原理来说,基本上是对的。 但实际情况不是这样,实际是这样的:
1. 首先Linux内核为了防止参数不定的情况? stack的起始地址是0xc000000-32*4096-??.
2. Linux内核使用Linux-gate作为系统调用入口,这个入口在固定位置,需要占用1页虚址
3. 还有动态库的情况,基本上应用程序使用动态库的占多数,所以应用程序加载的虚址一般从0x80xxxxxx开始,即text的起始地址是0x80xxxxxx
4. 应用程序运行中可能需要使用dlopen()打开动态库,其中的text+data+bss这又会占用你认为的heap+stack的空间
5. 最后,假设即使一个应用程序有超过1G的heap空间可以使用,如果你的系统使用512M内存+512M交换分区的组合,默认情况下最多只能malloc() 512/2+512(M)内存,如果我没有记错的话,这是内核的vm overcommit机制,我记得以前我写过一个这样的文档。可以通过/proc/sys/vm/overcommit_memory和/proc/sys/vm/overcommit_ratio调节。设想一下,如果你真的需要这么多内存来运行这个应用程序,即使分配到了1G的虚存,也不可能有这么多物理内存+交换分区使用。

下面是一个我机器上的例子:
[xiaozhaoz@xiaozhaoz_linux x86]$ cat /proc/version
Linux version 2.6.18 (xiaozhaoz@xiaozhaoz_linux) (gcc version 4.0.0 20050519 (Red Hat 4.0.0-) #5 PREEMPT Thu Sep 21 09:26:16 CST 2006
---------------------------------------------------------------------
[xiaozhaoz@xiaozhaoz_linux x86]$ readelf -l /bin/bash

Elf file type is EXEC (Executable file)
Entry point 0x805b600
There are 8 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  PHDR           0x000034 0x08047034 0x08047034 0x00100 0x00100 R E 0x4
  INTERP         0x000134 0x08047134 0x08047134 0x00013 0x00013 R   0x1
      [Requesting program interpreter: /lib/ld-linux.so.2]
  LOAD           0x000000 0x08047000 0x08047000 0xa1694 0xa1694 R E 0x1000
  LOAD           0x0a1694 0x080e9694 0x080e9694 0x057e8 0x0a108 RW  0x1000
  DYNAMIC        0x0a16a8 0x080e96a8 0x080e96a8 0x000d8 0x000d8 RW  0x4
  NOTE           0x000148 0x08047148 0x08047148 0x00020 0x00020 R   0x4
  GNU_EH_FRAME   0x0925d8 0x080d95d8 0x080d95d8 0x034cc 0x034cc R   0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x4

Section to Segment mapping:
  Segment Sections...
   00
   01     .interp
   02     .interp .note.ABI-tag .hash .dynsym .gnu.liblist .gnu.conflict .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame
   03     .ctors .dtors .jcr .dynamic .got .got.plt .data .dynbss .bss
   04     .dynamic
   05     .note.ABI-tag
   06     .eh_frame_hdr
   07
---------------------------------------------------------------------
[xiaozhaoz@xiaozhaoz_linux x86]$ ldd /bin/bash
        linux-gate.so.1 =>  (0xffffe000)
        libtermcap.so.2 => /lib/libtermcap.so.2 (0x00807000)
        libdl.so.2 => /lib/libdl.so.2 (0x0067a000)
        libc.so.6 => /lib/libc.so.6 (0x00528000)
        /lib/ld-linux.so.2 (0x0050a000)
---------------------------------------------------------------------
[xiaozhaoz@xiaozhaoz_linux x86]$ cat /proc/2599/maps
0050a000-00524000 r-xp 00000000 fe:00 2393276    /lib/ld-2.3.5.so
00524000-00525000 r--p 00019000 fe:00 2393276    /lib/ld-2.3.5.so
00525000-00526000 rw-p 0001a000 fe:00 2393276    /lib/ld-2.3.5.so
00528000-0064c000 r-xp 00000000 fe:00 2393277    /lib/libc-2.3.5.so
0064c000-0064e000 r--p 00124000 fe:00 2393277    /lib/libc-2.3.5.so
0064e000-00650000 rw-p 00126000 fe:00 2393277    /lib/libc-2.3.5.so
00650000-00652000 rw-p 00650000 00:00 0
0067a000-0067c000 r-xp 00000000 fe:00 2393279    /lib/libdl-2.3.5.so
0067c000-0067d000 r--p 00001000 fe:00 2393279    /lib/libdl-2.3.5.so
0067d000-0067e000 rw-p 00002000 fe:00 2393279    /lib/libdl-2.3.5.so
00807000-0080a000 r-xp 00000000 fe:00 2392133    /lib/libtermcap.so.2.0.8
0080a000-0080b000 rw-p 00002000 fe:00 2392133    /lib/libtermcap.so.2.0.8
08047000-080e9000 r-xp 00000000 fe:00 1638482    /bin/bash
080e9000-080ef000 rw-p 000a1000 fe:00 1638482    /bin/bash
080ef000-08136000 rw-p 080ef000 00:00 0          [heap]
b7dc2000-b7dcb000 r-xp 00000000 fe:00 2392117    /lib/libnss_files-2.3.5.so
b7dcb000-b7dcc000 r--p 00008000 fe:00 2392117    /lib/libnss_files-2.3.5.so
b7dcc000-b7dcd000 rw-p 00009000 fe:00 2392117  CE褡约旱目占渲小?inux-gate.so是一个不存在的文件,是内核的一个物理内存页,可以使用dd 读取出来,反汇编看看就知道了。

论坛徽章:
0
7 [报告]
发表于 2006-09-22 11:31 |只看该作者
CU又出问题了。
后面一段是:


[xiaozhaoz@xiaozhaoz_linux x86]$ cat /proc/2599/maps
0050a000-00524000 r-xp 00000000 fe:00 2393276    /lib/ld-2.3.5.so
00524000-00525000 r--p 00019000 fe:00 2393276    /lib/ld-2.3.5.so
00525000-00526000 rw-p 0001a000 fe:00 2393276    /lib/ld-2.3.5.so
00528000-0064c000 r-xp 00000000 fe:00 2393277    /lib/libc-2.3.5.so
0064c000-0064e000 r--p 00124000 fe:00 2393277    /lib/libc-2.3.5.so
0064e000-00650000 rw-p 00126000 fe:00 2393277    /lib/libc-2.3.5.so
00650000-00652000 rw-p 00650000 00:00 0
0067a000-0067c000 r-xp 00000000 fe:00 2393279    /lib/libdl-2.3.5.so
0067c000-0067d000 r--p 00001000 fe:00 2393279    /lib/libdl-2.3.5.so
0067d000-0067e000 rw-p 00002000 fe:00 2393279    /lib/libdl-2.3.5.so
00807000-0080a000 r-xp 00000000 fe:00 2392133    /lib/libtermcap.so.2.0.8
0080a000-0080b000 rw-p 00002000 fe:00 2392133    /lib/libtermcap.so.2.0.8
08047000-080e9000 r-xp 00000000 fe:00 1638482    /bin/bash
080e9000-080ef000 rw-p 000a1000 fe:00 1638482    /bin/bash
080ef000-08136000 rw-p 080ef000 00:00 0          [heap]
b7dc2000-b7dcb000 r-xp 00000000 fe:00 2392117    /lib/libnss_files-2.3.5.so
b7dcb000-b7dcc000 r--p 00008000 fe:00 2392117    /lib/libnss_files-2.3.5.so
b7dcc000-b7dcd000 rw-p 00009000 fe:00 2392117    /lib/libnss_files-2.3.5.so
b7dcd000-b7fcd000 r--p 00000000 fe:00 265187     /usr/lib/locale/locale-archive
b7fcd000-b7fce000 rw-p b7fcd000 00:00 0
b7fdd000-b7fdf000 rw-p b7fdd000 00:00 0
b7fdf000-b7fe5000 r--s 00000000 fe:00 327987     /usr/lib/gconv/gconv-modules.cache
b7fe5000-b7fe6000 rw-p b7fe5000 00:00 0
b7fe6000-b7fe7000 r-xp b7fe6000 00:00 0          [vdso]
bfc31000-bfc47000 rw-p bfc31000 00:00 0          [stack]
---------------------------------------------------------------------

注意看上面的虚存值,ld是按照elf中的信息加载到虚存的. 最后的内存maps中描述的很清楚。vdso就是linux-gate.so的映射,以前的内核版本直接映射到0xffffe000,新的为了使用kexec,都移到任务自己的空间中。linux-gate.so是一个不存在的文件,是内核的一个物理内存页,可以使用dd 读取出来,反汇编看看就知道了。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP