总结:

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中级教程2 - 图层

    Cesium中文网:http://cesiumcn.org/ | 国内快速访问:http://cesium.coinidea.com/ Cesium支持从几个标准服务绘制和添加高分辨率图像(地图)图层 ...

  2. vue文档1-VSCode介绍

    开发工具VSCode: Vue的开发工具用的是VSCode(Visual Studio Code),这款开发工具是微软官方出品,开源,免费,并且功能相当强大,使用者很多,插件相当丰富,是Vue开发的不 ...

  3. CSS基本语法(二)

    目录 CSS基本语法(二) 八.CSS复合选择器 1.后代选择器** 2.子选择器 3.并集选择器** 4.伪类选择器 链接伪类选择器 :focus伪类选择器 总结 九.CSS的元素显示样式 1.概念 ...

  4. Go 获取键盘输入,进制转换

    #### Go 获取键盘输入,进制转换 最近爱上<<珂矣的心灵独语>> 连续听一下礼拜也不觉得厌: 喜欢她的宁静与安然,喜欢她的坦荡与欢喜,喜欢她的禅意与智慧; ***撑着一苇 ...

  5. 集合框架-ListIterator接口

    1 package cn.itcast.p4.list.demo; 2 3 import java.util.ArrayList; 4 import java.util.Iterator; 5 imp ...

  6. python网络爬虫-python基础(三)

    python安装 Anaconda的python科学计算环境,只需要想普通软件一样安装就可以把python的环境变量.解释器.开发环境都安装到计算机中 除此之外anaconda还提供众多的科学计算的包 ...

  7. linux 环境变量配置方式

    linux 环境变量可以在多个文件中配置 说明: linux bash 运行模式分为两种: login shell 和non-login shell, 两种登录模式启动是加载的配置文件不一样. 1. ...

  8. NOIP2018 Day2T3 保卫王国

    首先不考虑强制要求的话是一个经典问题,令 \(f_{i, 0 / 1}\) 为 \(i\) 选或不选时以 \(i\) 为根的子树的最优答案.那么就有转移 \(f_{u, 0} = \sum f_{v, ...

  9. Docker版本Jenkins的使用

    一. 什么是Jenkins Jenkins是当前非常流行的一款持续集成工具,可以帮助大家把更新后的代码自动部署到服务器上运行. 二. 为什么用docker版的Jenkins Jenkins主要有三种安 ...

  10. 连接mysql出现“Unable to load authentication plugin 'caching_sha2_password”错误

    这是mysql 8.0版本才出现的问题,原因是mysql 8.0 默认使用 caching_sha2_password 身份验证机制 -- 从原来的 mysql_native_password 更改为 ...