总结:

1、句柄就是进程句柄表中的索引。
2、句柄是对进程范围内一个内核对象地址的引用,一个进程的句柄传给另一个进程是无效的。一个内核对象可用有多个句柄。
Windows之所以要设立句柄,根本上源于内存管理机制的问题,即虚拟地址。简而言之数据的地址需要变动,变动以后就需要有人来记录、管理变动,因此系统用句柄来记载数据地址的变更。

当一个进程被初始化时,系统要为它分配一个句柄表。该句柄表只用于内核对象 ,不用于用户对象或 GDI 对象。

。第一个句柄索引为4,第二个是8。

创建内核对象

当进程初次被初始化时,它的句柄表是空的。然后,当进程中的线程调用创建内核对象的函数时,比如 CreateFileMapping,内核就为该对象分配一个内存块,并对它初始化。这时,内核对进程的句柄表进行扫描,找出一个空项。由于表 3 - 1 中的句柄表是空的,内核便找到索引 4位置上的结构并对它进行初始化。该指针成员将被设置为内核对象的数据结构的内存地址,访问屏蔽设置为全部访问权,同时,各个标志也作了设置。

下面列出了用于创建内核对象的一些函数(不是个完整的列表):

HANDLE CreateThread(
PSECURITY_ATTRIBUTE psa,
DWORD dwStackSize,
LPTHREAD_START_ROUTINE pfnStartAddr,
PVOID pvParam,
DWORD dwCreationFlags,
PDWORD pdwThreadId); HANDLE CreateFile(
PCTSTR pszFileNAme,
DWORD dwDesiredAccess,
DWORD dwShareMode,
PSECURITY_ATTRIBUTES psa,
DWORD dwCreationDistribution,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile); HANDLE CreateFileMapping(
HANDLE hFile,
PSECURITY_ATTRIBUTES psa,
DWORD flPRotect,
DWORD dwMaximumSizeHigh,
DWORD dwMaximumSizeLow,
PCTSTR pszName); HANDLE CreateSemaphore(
PSECURITY_ATTRIBUTES psa,
LONG lInitialCount,
LONG lMaximumCount,
PCTSTR pszName);

用于创建内核对象的所有函数均返回与进程相关的句柄,这些句柄可以被在相同进程中运行的任何或所有线程成功地加以使用。该句柄值实际上是放入进程的句柄表中的索引,它用于标识内核对象的信息存放的位置。 因此当调试一个应用程序且观察内核对象句柄的实际值时,会看到一些较小的值,如 4,8 等。

每当调用一个将内核对象句柄接受为参数的函数时,就要传递由一个 Create*&函数返回的值。从内部来说,该函数要查看进程的句柄表,以获取要生成的内核对象的地址,然后按定义得很好的方式来生成该对象的数据结构。

 

如果传递了一个无效索引(句柄),该函数便返回失败,而 GetLastError 则返回 6(ERROR_INVALID_HANDLE)。由于句柄值实际上是放入进程句柄表的索引,因此这些句柄是与进程相关的,并且不能由其他进程成功地使用。

如果调用一个函数以便创建内核对象,但是调用失败了,那么返回的句柄值通常是 0(NULL)。发生这种情况是因为系统的内存非常短缺,或者遇到了安全方面的问题。不过有少数函数在运行失败时返回的句柄值是-1(INVALID_HANDLE_VALUE)。例如,如果 CreateFile 未能打开指定的文件,那么它将返回 INVALID_HANDLE_VALUE,而不是返回 NULL。当查看创建内核对象的函数返回值时,必须格外小心。特别要注意的是,只有当调用 CreateFile 函数时,才能将该值与 INVALID_HANDLE_VALUE 进行比较。下面的代码是不正确的:

HANDLE hMutex = CreateMutex(...);
if (hMutex == INVALID_HANDLE_VALUE) {
//这段代码不会执行,因为CreateMutex调用失败的时候返回的是NULL
}

同样的,下面的代码也不正确:

HANDLE hFile = CreateFile(...);
if (hFIle == NULL) {
//这段代码不会执行,因为CreateFile调用失败的时候返回的是INVALID_HANDLE_VALUE(-1)
}

关闭内核对象

无论怎样创建内核对象,都要向系统指明将通过调用 C l o s e H a n d l e 来结束对该对象的操作:

 
BOOL CloseHandle(HANDLE hobj); 

如果该句柄是有效的,那么系统就可以获得内核对象的数据结构的地址,并可确定该结构中的使用计数的数据成员。如果使用计数是 0,该内核便从内存中撤消该内核对象。

如果将一个无效句柄传递给 CloseHandle,将会出现两种情况之一。如果进程运行正常,CloseHandle 返回 FALSE,而 GetLastError 则返回 ERROR_INVALID_HANDLE。如果进程正在排除错误,系统将通知调试程序,以便能排除它的错误。

 

在 CloseHandle 返回之前,它会清除进程的句柄表中的项目,该句柄现在对你的进程已经无效,不应该试图使用它。无论内核对象是否已经撤消,都会发生清除操作。当调用 CloseHandle 函数之后,将不再拥有对内核对象的访问权,不过,如果该对象的使用计数没有递减为 0,那么该对象尚未被撤消。这没有问题,它只是意味着一个或多个其他进程正在使用该对象。当其他进程停止使用该对象时(通过调用 CloseHandle),该对象将被撤消。

假如忘记调用 CloseHandle 函数,那么会不会出现内存泄漏呢?答案是可能的,但是也不一定。在进程运行时,进程有可能泄漏资源(如内核对象)。但是,当进程终止运行时,操作系统能够确保该进程使用的任何资源或全部资源均被释放,这是有保证的。对于内核对象来说,系统将执行下列操作:当进程终止运行时,系统会自动扫描进程的句柄表。如果该表拥有任何无效项目(即在终止进程运行前没有关闭的对象),系统将关闭这些对象句柄。如果这些对象中的任何对象的使用计数降为 0,那么内核便撤消该对象。

因此,应用程序在运行时有可能泄漏内核对象,但是当进程终止运行时,系统将能确保所有内容均被正确地清除。另外,这个情况适用于所有对象、资源和内存块,也就是说,当进程终止运行时,系统将保证进程不会留下任何对象。

作者:Akkuman
链接:https://ld246.com/article/1518194894673
来源:链滴
协议:CC BY-SA 4.0 https://creativecommons.org/licenses/by-sa/4.0/

【Windows 操作系统】Windows 进程的内核对象句柄表的更多相关文章

  1. Windows进程的内核对象句柄表

    当一个进程被初始化时,系统要为它分配一个句柄表.该句柄表只用于内核对象 ,不用于用户对象或GDI对象. 创建内核对象 当进程初次被初始化时,它的句柄表是空的.然后,当进程中的线程调用创建内核对象的函数 ...

  2. windows内核对象句柄

    内核对象用于管理进程.线程和文件等诸多种类的大量资源,每一个内核对象都只是一个句内存快,它由操作系统内核分配,并只能右操作系统内核访问.这个内存块是一个数据结构,其维护着与对象相关的信息,其中少数成员 ...

  3. 【Windows 操作系统】 内核对象|句柄

    内核对象简介 内核对象就是 一些数据结构该结构用来描述存储内核中的一个内存块中的数据信息.   内存块是一种数据结构,其中的数据成员负责维护该对象的相应信息,这个数据结构以及其中的数据成员只能由内核访 ...

  4. Windows API学习---线程与内核对象的同步

    前言 若干种内核对象,包括进程,线程和作业.可以将所有这些内核对象用于同步目的.对于线程同步来说,这些内核对象中的每种对象都可以说是处于已通知或未通知的状态之中.这种状态的切换是由Microsoft为 ...

  5. Windows核心编程笔记之内核对象

    0x01 子进程继承父进程内核对象句柄 父进程 #include <Windows.h> #include <iostream> #include <strsafe.h& ...

  6. 内核对象&句柄&泄漏&检测

    今天看到这个问题如何评价王垠的 <讨厌的 C# IDisposable 接口>? - 王垠(人物),答案被歪到windows 内核对象和句柄,答案中谈的太浅显而且有误.翻出陈年老文章(此文 ...

  7. 内核对象&句柄

    目录 1 内核对象的概念 2 内核对象的使用计数 3 句柄 4 句柄表   项目工程代码中设计句柄的使用,一时不知句柄是何物,通过查阅自学之后,对句柄及其使用有一个初步的了解.分享出来,算是抛砖引玉吧 ...

  8. 内存块是一种数据结构,内核对象&句柄

    内核对象&句柄 目录 1 内核对象的概念 2 内核对象的使用计数 3 句柄 4 句柄表   项目工程代码中设计句柄的使用,一时不知句柄是何物,通过查阅自学之后,对句柄及其使用有一个初步的了解. ...

  9. 【windows 操作系统】进程控制块(PCB)

    转载地址:https://blog.csdn.net/qq_38499859/article/details/80057427一.目录文章目录    操作系统3 ----进程控制块(PCB)详解    ...

随机推荐

  1. Cesium应用篇--添加雨雪天气

    作为一个三维地球,在场景中来点雨雪效果,貌似可以增加一点真实感.Cesium官网Demo中有天气系统的实例,用的是Cesium中的粒子系统做的.效果如下图所示,粒子系统的本质是向场景中添加了很多物体, ...

  2. shell $用法

    $0 这个程式的执行名字$n 这个程式的第n个参数值,n=1..9$* 这个程式的所有参数,此选项参数可超过9个.$# 这个程式的参数个数$$ 这个程式的PID(脚本运行的当前进程ID号)$! 执行上 ...

  3. Nginx怎么处理请求的?

    nginx接收一个请求后,首先由listen和server_name指令匹配server模块,再匹配server模块里的 location,location就是实际地址.   server { # 第 ...

  4. kubernetes之部署dashboard 和heapster

    部署dashboard之前,先确保traefik https方式部署成功,这样就可以通过 https 域名的方式访问dashboard,无需kube-proxy转发了.假设traefik-ingres ...

  5. How to check in Windows if you are using UEFI

    You might be wondering if Windows is using UEFI or the legacy BIOS, it's easy to check. Just fire up ...

  6. host文件以及host的作用

    什么是HOST文件:Hosts是一个没有扩展名的系统文件,其基本作用就是将一些常用的网址域名与其对应的IP地址建立一个关联"数据库",当用户在浏览器中输入一个需要登录的网址时,系统 ...

  7. contos 6.9 和 centos7 配置docker?

    一.contos 6.9 配置docker? 1.检查centos的内核,因为目前docker的版本所支持的centos最低内核版本为2.4 // uname -r // 2.6.32-696.el6 ...

  8. PyTorch 介绍 | BUILD THE NEURAL NETWORK

    神经网络由对数据进行操作的layers/modules组成.torch.nn 命名空间提供了所有你需要的构建块,用于构建你自己的神经网络.PyTorch的每一个module都继承自nn.Module. ...

  9. react之withRouter的作用

    withRouter的作用:把不是通过路由切换过来的组件,将react-router的history.location和match三个对象传入到props对象上: 默认情况下必须是经过路由匹配渲染的组 ...

  10. bom-对话框

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...