回顾16bit windows时代,它们之间的区别是很大的。
在16bit windows中,内存是通过一组叫"selector"(选择子)的值来访问的,每个selector最大可以寻址64k。有一个默认的selector被称为"data selector",被称为"near pointors"(近指针)的操作就是在这个默认data selector上进行的。例如,你有一个"near pointor" p=0x1234,你的data selector的值为0x012f,那么当你写*p时,你访问的是内存012f:1234。(当你定义一个指针时,默认为近指针。如果你想定义一个far pointor,你必须显示的使用far关键字)。
注(重要):近指针总是和一个selector关联着,通常是data selector。
函数GlobalAlloc用来分配一个selector,这个selector可以被用来访问你申请的那块内存。(如果你申请的内存数量大于64k,一些有趣的事情就会发生了。但是在这里,我不想讨论它。)你可以通过"far pointor"来访问这个selector中的内存。"far pointor"是由一个selector和一个near pointor组成的。(记住,near pointor总是和一个selector关联在一起的。当你把一个near pointor和一个合适的selector捆绑在一起后,你就得到了一个far pointor。)
任何一个程序或DLL的实体都有他们自己的data selector,它被称做HINSTANCE。对于一个可执行程序来说,它代码的默认data selector就是它程序实体的HINSTANCE;同样对于一个DLL来说,它代码的默认data selector就是那个DLL的HINSTANCE。所以,如果你有一个near pointor p,在一个可执行程序里,通过*p访问它,被访问的内存就是相对于那个程序实体的HINSTANCE的。如果你在一个DLL中访问它,你访问的就是相对于DLL HINSTANCE的内存。
被默认selector引用的内存,可以通过函数LocalInit把它转换成"Local Heap"。初始化local heap基本上是一个应用程序或者DLL启动时所需要做的第一件事情。(对于DLL来说,这基本上是它所需要做的唯一一件事)一旦有了local heap,你就可以通过LocalAlloc从中分配内存。函数LocalAlloc返回一个相对于默认selector的近指针(near pointor),所以如果你从一个可执行程序中调用它,它就从可执行程序的HINSTANCE中分配内存;如果从DLL中调用它,它就从DLL的HINSTANCE中分配内存。
如果你那时很聪明,你会意识到LocalAlloc不仅仅只能从各种HINSTANCEs中分配内存。你所需要做的就是用GlobalAlloc得来的selector替换默认selector,然后调用LocalAlloc,最后恢复默认selector。这个过程能够给你一个不是相对于默认selector的near pointor。这个过程有点tricky,但是,如果你聪明并且仔细,你可以避免自己陷入麻烦。
综上所述,我们可以知道,在16bit windows中,LocalAlloc和GlobalAlloc是完全不一样的,LocalAlloc返回一个near pointor,而GlobalAlloc分配一个selector。
那些被传递于不同模块间的pointors,必须是far pointor,因为不同的模块有不同的默认selector。如果你想把一块内存的拥有权转给另一个模块,你必须使用GlobalAlloc,因为接受者可以调用GlobalFree去释放这块内存。
在Win32系统中,LocalAlloc和GlobalAlloc不同的遗迹依然存在。如果你有个从16bit windows继承来的函数,并且这个函数需要转换内存的归属权,它依然会使用HGLOBAL。与粘贴板相关的函数,是这种模式的经典案例。如果你把一块内存放到粘贴板上,这块内存必须的是使用HGLOBAL分配得来,因为你正把一块内存传递给粘贴板,只有这样,粘贴板才能使用GlobalFRee释放这块内存当它不再需要它时。同一原因,通过STGMEDIUM传递的内存也是使用HGLOBAL的模式。
甚至在Win32中,你依然得小心区分local heap和global heap。从其中之一得到的内存,不能在另一个中释放。实际上,它们之间功能性的区别基本上已经消失,在某点上,语义上也基本相同。步入win32之后,关于near pointor和far pointor之间所有怪异的事情都不存在了。但是local heap相关的函数和global heap相关的函数依然是两组完全不同的借口。
我将在接下来的几篇文章中,详细讨论16bit 内存管理器。即使你们不需要了解它们,知道一些背景知识也有助于理解win32内存管理器的设计思想(原因)。我们今天已经看到了一些,比如剪切版的内存管理方式。
阅读(4252) | 评论(0) | 转发(0) |