[转]探索Windows的内存机制

转载 2007年10月14日 14:08:00
内存是操作系统的核心部分,所以我们非常有必要了解内存的分配机制。在DOS下,访问内存的指针是用段地址:偏移量来表示,所有程序共用一个内存空间,由低向高分配内存空间,所以任何程序都可以随便修改内存中的数据,包括不属于自己程序的内存空间和中断向量表。而且所有程序被局限在1M的基本内存(Base Memory)中,不能直接访问扩充内存。对于Windows下的程序来说,它所访问的内存地址不再是真实的。而是虚拟的、独立的全平坦式(flat)的内存空间。如一个32位的程序可访问内存地址是0x00000000到0xffffffff(4G),指针不再存储段地址。所谓独立,指的是当进程A加载到内存0x400000处时,进程B加载到内存的地址时一样是0x400000,两者的地址空间是相互独立的。程序访问内存地址时,由Windows自动换算为真实的内存地址。这样,程序A是无法直接访问程序B的内存空间的,也就提高了系统的稳定性。
    其实,在这4G的内存地址中,我们能使用的内存地址不到一半。我们的程序是无法分配到0x80000000以上的内存地址的,这2G的内存地址都是被系统占用,是只读的。如果一个应用程序企图对大于0x80000000的内存地址进行写操作,则会产生"非法操作"。例如: char *pstr; if(pstr!=NULL) *ptr='a'; 这里声明了一个指针,在没有对其初始化时,它指向0xCCCCCCCC(这里很奇怪不知为什么所有没初始化的变量,其值都为0xCCCCCCCC),所以不为空,因而执行 *pstr=“a” 。由于0xCCCCCCCC在0x80000000以上,产生了一个“非法操作”,这就是有的朋友常犯的错误。
    在Win2000中,用户可以使用0x80000000以上的1G地址(在Boot.ini 中加上参数 /3G) 不过似乎对于普通程序员来说,是没有什么意义的。 Win9x内存中与Win2000的内存分配略有不同。在Win98下,应用程序可使用的内存是从0x400000开始,而在Win2000下,是从0x100000开始。可是加载应用程序时,都是加载到0x400000 。试试这段代码: BYTE buff[0x300]; DWORD dwRead; ReadProccessMemory(GetCurrentProcess(),(PVOID)0x400000,buff,0x300,&dwRead); 请把Buff输出到文件中,你会发现正好是你的应用程序的文件头。 
    Windows的内存分配是以页(page)为单位(与磁盘的扇区很相似),每一页的大小因CPU而异。我们常用的PC机是x86构架,每页为4096字节,可以用GetSystemInfo()函数得到页面大小。一个内存块由多个页面组成。每个页都有一个访问属性: PAGE_NOACCESS 不可访问 PAGE_READONLY 只读 PAGE_READWRITE 读写 PAGE_EXECUTE 可执行 …… 我们可以用: DWORD VirtualQuery( LPCVOID lpAddress, // 内存地址 PMEMORY_BASIC_INFORMATION lpBuffer, // 内存地址信息 DWORD dwLength // lpBuffer 的大小,也就是结构 MEMORY_BASIC_INFORMATION 的大小 ); 来得到某个内存块的状态。使用 VirtualQueryEx() 还可以访问其它进程的内存分配信息。要注意的是这两个函数是得到一个内存块的信息,而不是一个页的信息。在Win9x,当对一个低于0x80000000地址进行写操作时,即使此内存地址为只读(PAGE_READONLY)或是此内存根本就没有分配,Win9x一般也不会报错,这样使得Win9x兼容性好了些,但也使Win9x非常脆弱。在Win2000下则严格遵守页面属性规则,如果你企图对非写属性的内存地址进行操作时,会立刻被中断。这就是为什么很多程序能在Win9x下运行,而转到Win2000下就出现非法操作的原因。虽然我们不能直接读取其它进程的内存空间,但Windows也还是给我们留下了一个后门: ReadProcessMemory()、WriteProcessMemory()。这两个函数可以直接对其它进程的内存进行读写操作。也许你会发现,如果Windows同时启动两次一个相同的应用程序(如同时启动两个Visual Studio),第二次起动的速度明显快于第一次。这是因为,虽然每个程序的内存空间是独立的,但它们有一部分内存是只读的,是可以几个进程共享包括放在0x80000000内存空间以上的系统服务。Windows提供这个功能可以很有效的节省内存空间,提高系统的效率。谈到这里,我们又有问题了,如何在两个进程之间的正常的进行数据交换,而不是用ReadProcessMemory的WriteProcessMemory去强行读写呢? 常用的方法是用MapViewOfFile()把文件映射到内存中,其它进程可以用OpenViewOfFile()来访问,或是用Windows的DDE数据传输协议。还有一种访问是放到DLL中,通过: #pragma data_seg("AllUser") ....//数据 #pragma data_seg() #pragma comment(linker,"/SECTION:AllUser,SRW") // SRW 为共享读写 把某个内存块设置为公用内存,那么就可象使用全局变量一样访问此内存空间。 
    如果有这样一个问题,下面的Struct 在内存中占用多大的字节。 struct{ char a[2]; int b; }abc; 也许你会这样回答,在Windows下Char占一个字节,Int占4个字节,所以是6个字节。其实如果我们用Sizeof得到的大小是8个字节。因为在Windows下对结构变量分配内存空间缺省大小是8的倍数。它不再象DOS一样按本身结构的大小分配,这是由于CPU访问对齐的数据速度要比访问非对齐数据速度要快好几倍。如果你的数据量太大,希望按真实大小对结构分配空间,则可以设置 Project => Setting => C/C++ => Category => Code Generation => struct member alignment 将其设为1就行了。分配非内存对齐的变量同样也会影响执行速度,如: char *pstr=(char *)malloc(5); DWORD *pdw=(DWORD *)(pstr+1); PDW指针指向的就是一个奇数地址,对PDW操作时就很费时。
    小结:对于一个VC程序员来说,很多程序的错误都出现在内存分配上,如未经检查就使用一个空指针等,如果能很好的管理、分配你程序的内存空间,你的程序将会少去一些不必要的错误。 

全面介绍Windows内存管理机制及C++内存分配实例

转自:http://blog.csdn.net/yeming81/article/details/2046193 本文基本上是windows via c/c++上的内容,笔记做得不错。。 本文背景...
  • vsooda
  • vsooda
  • 2013年05月30日 09:44
  • 21543

Windows内存原理与内存管理

1.进程地址空间     Windows为每个进程分配了4GB的虚拟地址空间,让每个进程都认为自己拥有4GB的内存空间,4GB怎么来的? 32位 CPU可以取地址的空间为2的32次方,就是4GB. ...
  • dongpanshan
  • dongpanshan
  • 2015年07月03日 16:17
  • 1224

内存分段机制与分页机制

(一):逻辑地址(Logical Address)          指由程式产生的和段相关的偏移地址部分。例如,你在进行C语言指针编程中,能读取指针变量本身值(&操作),实际上这个值就是逻辑地...
  • u011580175
  • u011580175
  • 2017年01月12日 14:29
  • 177

C/C++内存分配机制

http://hi.baidu.com/lcplj123/item/e984cd0f921e39c12e4c6baa 1.C语言中的内存机制 在C语言中,内存主要分为如下5个存储区: (1)栈(S...
  • T_W_S
  • T_W_S
  • 2013年05月13日 09:21
  • 2941

linux 内存分配机制

这几天在观察apache使用内存情况,所以特意了解了下linux的内存机制,发现一篇写得还不错。转来看看。 一般来说在ps aux中看到的rss就是进程所占用的物理内存。但是如果将所有程序的rss加...
  • koozxcv
  • koozxcv
  • 2015年10月28日 17:02
  • 1719

深入理解Linux内存管理机制

深入理解Linux内存管理机制(一) 浏览次数:595次2012年08月03日淘宝核心系统团队博客字号: 大 中 小 分享到:QQ空间新浪微博腾讯微博人人网豆瓣网开心网更多1 深...
  • haiross
  • haiross
  • 2014年08月29日 10:45
  • 1997

详解Windows内存分页机制

原文链接: http://bbs.pediy.com/showthread.php?t=135274 标 题: 【原创】详解Windows内存分页机制 作 者: 莫灰灰 时 间: 2011-06-...
  • qiaoli278141408
  • qiaoli278141408
  • 2015年03月14日 13:53
  • 1149

关于内存的分段与分页机制

分段机制:   在8086时期,寄存器是16位,无法存放20位的物理地址,为了解决这问题,人们提出了分段机制,分段机制就是将内存分段,每段大小64kb(正好由16位表示),在段寄存器中放入段基址,然...
  • Scythe666
  • Scythe666
  • 2016年07月15日 14:49
  • 2244

Java 内存分配全面浅析

本文将由浅入深详细介绍Java内存分配的原理,以帮助新手更轻松的学习Java。这类文章网上有很多,但大多比较零碎。本文从认知过程角度出发,将带给读者一个系统的介绍。 进入正题前首先要知道的是Java程...
  • shimiso
  • shimiso
  • 2013年02月20日 17:54
  • 79286

Android内存机制分析

Java的堆是一个运行时数据区,类的(对象从中分配空间。这些对象通过new、newarray、anewarray和multianewarray等指令建立,它们不需要程序代码来显式的释放。堆是由垃圾回收...
  • i_lovefish
  • i_lovefish
  • 2013年11月10日 18:14
  • 1072
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:[转]探索Windows的内存机制
举报原因:
原因补充:

(最多只允许输入30个字)