博客主机
A-A+

内存的管理

2011年04月24日 柴房 暂无评论
  • 进程空间Win32的可执行文件在加载后,系统将为它建立一个它自己的虚拟内存空间,即进程空间,其容量达4G(64位系统中将更大,但我想64位的程序应该不叫做Win32程序了吧?)。这4G的空间划分为了几个区域,对于win98和win2000是不尽相同的。
                               Window2000              Windows98
        NULL指针分配分区       0x00000000~0x0000ffff   0x00000000~0x00000fff
        MS-DOS/Win16兼容分区   无                      0x00001000~0x003fffff
        用户分区               0x00010000~0x7ffeffff   0x00400000~0x7fffffff
        禁止访问分区(64K)    0x7fff0000~0x7fffffff   无
        共享(MMF)分区        无                      0x80000000~0xbfffffff
        内核方式分区           0x80000000~0xffffffff   0xc0000000~0xffffffff

    (上表资料来自:《Windows核心编程》)

    1. NULL指针分区是NULL指针的地址范围。对这个区域的读写企图都将引发访问违规。
    2. DOS/WIN16分区是98中专门用于16位的DOS和windows程序运行的空间,所有的16位程序将共享这个4M的空间。Win2000中不存在这个分区,16位程序也会拥有自己独立的虚拟地址空间。有的文章中称win2000中不能运行16位程序,是不确切的。
    3. 用户分区是进程的私有领域,Win2000中,程序的可执行代码和其它用户模块均加载在这里,内存映射文件也会加载在这里。Win98中的系统共享DLL和内存映射文件则加载在共享分区中。
    4. 禁止访问分区只有在win2000中有。这个分区是用户分区和内核分区之间的一个隔离带,目的是为了防止用户程序违规访问内核分区。
    5. MMF分区只有win98中有,所有的内存映射文件和系统共享DLL将加载在这个地址。而2000中则将其加载到用户分区。
    6. 内核方式分区对用户的程序来说是禁止访问的,操作系统的代码与此。内核对象是否也驻留在此?我认为应该是的,因为应用程序不能直接访问内核对象。但是关于这点我没找到有关的叙述,不知哪位大侠有确切的依据?另外要说明的是,win98中对于内核分区本也应该提供保护的,但遗憾的是并没有做到,因而98中程序可以访问内核分区的地址空间。
  • 进程的内存布局见下图.
    ===============================================================================
    
                  -----------------
      高地址      |               | ---> 命令行参数和环境变量 (只读)
                  -----------------
                  |      栈       |
                  |- - - - - - - -|
                  |      | |      |
                  |      \ /      |
                  |               |
                  |               |
                  |      / \      |
                  |      | |      |
                  |- - - - - - - -|
                  |      堆       |
                  |---------------|
                  | 未初始化的变量|
                  |     (bss)     | ---> 由 exec 初始化为零
                  |---------------|
                  | 初始化后的变量|  \
                  |---------------|   |
                  | text(数据区)|   | 由 exec 从程序中读取
              |               |  /
                  |---------------|
      低地址    |   代码区      |
                  |---------------|
    
    ===============================================================================
    (见http://263.aka.org.cn/Lectures/002/Lecture-2.1.6/Lecture-2.1.6/proc.html
    http://www.csdn.net/Develop/article/15%5C15747.shtm)
    1. 每一个进程在创建时都分配一个静态存储区域、一个堆和一个栈。
    2. 静态存储区域用于存储进程的全局变量和静态变量;这个对于理解MFC的theApp对象也挺有帮助的。全局变量和静态变量“从静态存储区域分配。程序在编译的时候就已经分配好内存的分布,这块内存在程序的整个运行期间都存在。”(见http://www.fanqiang.com/a4/b2/20020719/060200272.html)
    3. 堆可以动态分配内存。1)“程序在运行的时候用malloc或new从堆上动态申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。”(见http://www.fanqiang.com/a4/b2/20020719/060200272.html)

      2)“堆应该是保留的一段内存空间,在进程初始化的时候,系统会提交一部分物理存储。进程的堆的初始大小默认是1MB,这个可以在连接时用/HEAP开关自己控制。物理存贮的提交和回收应该是由堆管理器来管理的。”“堆应该是自动增长的。”“我们说的“自动生长”指的是在预先保留的全部堆空间都不够用的时候,重新来从自由区域保留。”(见http://www.pcvc.net/category/content.asp?sendid=118)

    4. 每一个函数都可以对栈操作,用于存储参数和局部变量。1)“在执行函数时,函数的参数和函数内的局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。”(见http://www.fanqiang.com/a4/b2/20020719/060200272.html)

      2)“(在函数内)声明变量/数组的方式,是在栈中分配内存。”“当调用完此函数返回的时候,栈空间自动被收回,其中的内容也就全部无效了。”(见http://www.pcvc.net/category/content.asp?sendid=114)

      例子:(引用朱茂盛提供的)

      1)定义函数

      char *testfunc()

      {

      char *pret="return character";

      return pret;

      }

      然后调用

      char *pp = testfunc();

      otherfunc();

      printf(pp);

      这样有问题吗?

      2)定义函数

      char *testfunc()

      {

      char pret[]="return character";

      return pret;

      }

      然后调用

      char *pp = testfunc();

      otherfunc();

      printf(pp);

      这样呢?

      分析:1)中虽然变量pret分配在栈中,但"return character"是分配在进程的数据区的,在整个进程的生命期内有效;2)中"return
      character"是数组的内容,是分配在栈中的,一旦出了这个函数,就从栈中释放。所以1)中没问题而2)中有问题。

    5. 有人说:“DLL 可 以 有 自 己 的 数 据 段, 但 是 它 没 有 堆 栈 段, 使 用 的 是 调 用 程 序 的 堆 栈。”(见http://www.2000n.com/02.htm) 也有人说:“DLL有自己的堆栈”。(见http://www.csdn.net/Develop/article/15%5C15747.shtm

      而朱茂盛说:在DLL中的函数里面分配的空间,是不允许在调用DLL的程序里面释放的。这么说来,DLL确实是有自己的堆栈的。

    6. 线程具有自己的内存布局。“进程中每个线程都有自己的堆栈,这是一段线程创建时保留下的地址区域。”(见http://www.pcvc.net/category/content.asp?sendid=118)
标签:

给我留言

Copyright © 小小的数据技术梦想 保留所有权利.   Theme  Ality 浙ICP备12043346号-1

用户登录

分享到: