宝哥软件园

手柄是什么?句柄在窗口结构中的作用

编辑:宝哥软件园 来源:互联网 时间:2021-09-02

手柄是什么?在Windows中,句柄的存在就像指针的识别一样,但这个答案说明它不是你所需要的。闲暇之余,笔者摘录了以下Windows手柄的讲解。用户可以用咖啡读取Windows结构中手柄的函数表达式。

句柄是什么?Windows结构体里面句柄的作用

在这里,我列出了条目中句柄的不当叙述。至于怎么无视他们,继续往下看你就明白了:

句柄是什么?

Windows之所以要设置句柄,根本上是因为内存管理机制的问题——虚拟地址。简而言之,数据的地址需要改变。变更后需要有人记录管理变更(就像户籍管理一样),所以系统使用句柄记录数据地址的变更。

如果你想更透彻地了解句柄,我可以告诉你,句柄是指针的指针。

一般来说,我们说句柄是Windows用来标识应用程序创建或使用的对象的唯一整数。这个句子没有问题,但是如果你想把这个句子映射到一个特定的记忆结构,你就做不到。让我们详细讨论一下什么是Windows中的句柄。

一、虚拟内存结构

我们知道,CPU通过寻址来访问内存。32位CPU的寻址宽度为0~0xFFFFFFFF,计算出的大小为4G,也就是说最大支持的物理内存为4G。但是在实践中存在这样的问题,程序需要使用4G内存,但是可用的物理内存小于4G,导致程序不得不减少内存占用。

为了解决这个问题,现代中央处理器引入了内存管理单元。

MMU的核心思想是用虚拟地址代替物理地址,即CPU在寻址时使用虚拟地址,MMU负责将虚拟地址映射到物理地址。MMU的引入,解决了物理内存的限制。对于程序来说,就好像是在用4G内存。

内存分页是一种基于MMU的内存管理机制。它将虚拟地址和物理地址按照固定的大小(4K)划分为页面和页面框架,并确保页面和页面框架的大小相同。这种机制在数据结构方面,保证了内存访问的高效率,使操作系统能够支持不连续的内存分配。当程序内存不足时,您也可以将不常用的物理内存页面转移到其他存储设备,如磁盘。这就是熟悉的虚拟记忆。

1、虚拟地址与物理地址需要通过映射,为了让中央处理器正常工作。

映射需要存储映射表。在现代CPU架构中,映射关系通常存储在物理内存中一个叫做页表的地方。

下图:

句柄是什么?Windows结构体里面句柄的作用

从这个图中,我们可以清楚地看到CPU、页表和物理内存之间的交互关系。

进一步优化,引入了TLB(翻译后备缓冲器)。

从上一节可以看出,页表存储在内存中。我们知道CPU通过总线访问内存,肯定比直接访问寄存器慢。

为了进一步优化性能,现代CPU架构引入TLB缓存一些频繁访问的页表内容。

下图:

句柄是什么?Windows结构体里面句柄的作用

中间加了一个TLB。

2、为什么要支持大内存分页?

毫无疑问,TLB是有限的。当超过TLB的内存限制时,就会出现TLB未命中,然后OS会命令CPU访问内存中的页表。如果TLB失误频繁发生,程序的性能将迅速下降。

为了允许TLB存储更多的页面地址映射,我们的方法是增加内存页面大小。

如果一个页面为4M,与一个页面4K相比,前者可以使TLB商店多1000个页面地址映射,性能提升相当可观。

简而言之,虚拟内存在内存的逻辑地址和物理地址之间建立了一个对应表。读写逻辑地址对应的物理内存内容,需要查询相关的页表(当然也有段和段页对应的方式,但原则上都是一样的),找到逻辑地址对应的物理地址进行相关操作。我们常见的内存分配接口,比如对程序员开放的malloc,都获取逻辑地址,c指针也指向逻辑地址。

这种虚拟内存的优点很多。这里以连续内存分配和可移动内存为例。

首先,我们来谈谈连续内存分配。我们经常需要分配一个连续的内存结构,比如一个数组,可以通过指针循环来读取,但是经过多次分配和释放,物理内存实际上已经被破坏了,如下图所示

句柄是什么?Windows结构体里面句柄的作用

图中白色为可用物理内存,黑色为其他程序占用的内存。现在需要分配一个12大小的连续内存,所以物理内存中显然没有这么大的连续内存。这时我们可以看到,通过页表的对应方式,我们可以很容易的得到逻辑地址处的12大小的连续内存。

再来说说可移动内存。我们在使用GlobalAlloc等函数时,经常会指定GMEM _ mobilize和GMEM_FIXED参数,这让人们很头疼,也无法理解它们的含义。

实际上,这里的可移动和固定都是指的逻辑地址。GMEM _可移动意味着允许操作系统(或应用程序)管理内存堆(逻辑地址)。必要时,操作系统可以移动内存块以获得更大的块,或者合并一些空闲的内存块,也称为“垃圾回收”,可以提高内存的利用率。这里的地址指的是逻辑地址。类似地,分配12大小的连续内存。在某种状态下,存储器结构如下

句柄是什么?Windows结构体里面句柄的作用

显然,此时不可能分配12个连续大小的内存,但是如果这里的所有逻辑地址都被指示为GMEM _可移动,操作系统将在此时管理逻辑地址,并获得以下结果:

句柄是什么?Windows结构体里面句柄的作用

此时,实现了逻辑地址的移动,这当然比物理存储器的移动要便宜得多。但是,聪明的朋友有没有问,如果内存是在逻辑地址中移动的,那么实际的访问数据就不会被混淆,你能找到自己分配的实际物理内存数据吗?等等,别担心,这是把手能做的。

GMEM_FIXED表示允许内存块在物理内存中移动,但逻辑地址必须保持不变。在早期的16位Windows操作系统中,不支持物理内存中的内存移动,所以禁止使用GMEM_FIXED,这一点你现在可能还不会意识到。

事实上,当使用GlobalAlloc分配内存时,通过指定GMEM_FIXED参数返回的句柄是指向内存分配的内存块的指针。你明白吗?然后看看下面的手柄结构,你就明白了。

二、句柄结构

在解释上面的虚拟内存结构的过程中,我们提出了几个问题:为什么MOVABLE的内存访问不是混沌的,为什么FIXED的内存是指向分配的内存块的指针。

其实,虽然Windows没有给出源代码,我们还是可以一窥一些头文件,MSDN和早期Windows的内存分配功能。

一般句柄在Winnt.h头文件中定义:

01#ifdef STRICT

02typedef void * HANDLE

03 #定义DECLARE_HANDLE(name)结构名# # _ _ { int unused};typedef结构名称# # _ _ *名称

04 #其他

05typedef PVOID HANDLE

06 #定义DECLARE_HANDLE(名称)typedef HANDLE名称

07#endif

08typedef HANDLE * PHANDLE

复制代码

#ifdef STRICT

typedef void * HANDLE

#define DECLARE_HANDLE(name)结构名##__ { int未使用;};typedef结构名称# # _ _ *名称

#否则

typedef PVOID HANDLE

#定义DECLARE_HANDLE(名称)typedef HANDLE名称

#endif

typedef HANDLE * PHANDLE

更多资讯
游戏推荐
更多+