网易首页 > 网易号 > 正文 申请入驻

微软为什么不用指针,而要多绕一层?

0
分享至


本文来自微信公众号: 宇众不同的露萱 ,作者:宇众不同的露萱

大概是在七八年前,我当时在学习Unix系统的内核代码,特别是open()返回的那个简单至极的整数文件描述符(File Descriptor)。那时候身边不少做Windows开发的朋友,提到系统底层,嘴里永远绕不开一个词:HANDLE。

一个指针大小的32位或64位无符号整数,指向一个在用户态完全看不见的内核对象。

当时我其实有一个很粗暴的偏见:Windows搞出HANDLE,无非就是微软习惯了搞封装、搞抽象,非要把原本简单的整数索引包装成某种看起来很“面向对象”的东西。甚至在很长一段时间里,我都觉得它只是C++时代产物下的某种过度设计。

直到后来我去翻早期微内核与操作系统设计的历史,尤其是阅读Dave Cutler(Windows NT的首席架构师)在VMS和NT时代的设计记录,我才意识到,我以前完全理解错了。

HANDLE不是微软为了秀面向对象抽象而凭空发明出来的。它的出现,本质上是一场关于“谁有权解释内核内存”的死斗。

在1980年代末,Dave Cutler带着一帮DEC的工程师被比尔·盖茨挖到微软开荒Windows NT时,他们面临的硬件环境和设计目标,和Linus Torvalds后来写Linux时有着微妙但决定性的不同。

当时的Unix哲学非常优雅,“一切皆文件”。你打开一个文件,系统给你一个fd(实际上就是进程文件描述符表里的一个数组下标)。要读取数据?read(fd,buff,size)。

这种设计在C语言的纯粹世界里美得像诗。但这种优雅建立在一个隐性假设上:所有的资源,在语义上都可以被抽象成字节流。

但NT设计之初,目标就不是只做一款“更好的Unix”。微软当时要面对的是极其混乱的商业计算环境:要支持多处理器(SMP)、要支持复杂的进程间同步、要支持精细到用户级的权限控制,还要在同一个内核上模拟POSIX、OS/2和Win32多种子系统。

如果你去仔细看NT内核的对象管理器(Object Manager)设计,你会发现一个很残酷的事实:

在操作系统内核里,信号量(Semaphore)、互斥锁(Mutex)、命名管道(Named Pipe)、物理内存映射(Section Object)、甚至是进程(Process)和线程(Thread)本身,它们根本无法被平滑地抽象成“字节流”。

一个线程对象,它有自己的执行上下文、挂起计数、优先级、亲和性掩码(Affinity Mask)。你不可能对一个线程去read()或者write()。

如果你强行把所有东西都套进文件描述符的壳子里,你很快就会碰到那个Unix社区折腾了几十年的老坑:ioctl()爆炸。所有无法用字节流表达的控制逻辑,最后都会变成一堆堆难以维护的二进制控制码。

如果不把所有资源都看作文件,那内核资源在用户态应该怎么表达?

最直白的做法,是直接给用户态返回一个内核对象的内存指针。

在C语言占据统治地位的年代,这种诱惑太大了。如果CreateThread直接返回一个ETHREAD结构体的指针,用户态程序要查询线程状态,直接thread->State读一下不就行了吗?连系统调用的开销都省了。

但Cutler他们在DEC时代就已经踩过这个血窟痛坑。

一旦你把内核结构的内存地址暴露给用户态,不管你加了多少层内存保护,用户程序就会不可避免地对这个地址产生依赖。哪怕你禁止写入,用户态代码也会开始依赖这个指针的偏置(Offset),依赖结构体里某个字段的大小。

后果就是:操作系统内核将永远无法重构。内核只要改动一个字段的位置,全天下所有的应用软件都会崩溃。

更致命的是安全。用户态进程是一个完全不可信的黑暗森林。如果传入一个指针,内核每次使用它,都必须做复杂的寻址检查、页面校验、抢占防御。如果用户态故意传进来一个精心构造的伪造指针,内核一不小心解引用,整个系统就直接Blue Screen。

所以,内核必须建立一道绝对隔离的墙。

这就是HANDLE真正诞生的时刻。

在Windows NT的设计里,HANDLE在逻辑上是一个间接表(Handle Table)的索引,但在语义上,它是一个携带了访问权限(Access Mask)的能力令牌(Capability Token)。

很多人以为HANDLE只是个指针掩码或者简单的数组下标,但其实它背后的机制非常硬核。

当你的进程调用OpenProcess时,内核做了三件事:

发现这个设计精妙的地方了吗?

用户态拿到的HANDLE,本质上是一串没有任何物理意义的符号。你把它加一、减一、或者强转成指针,对内核来说毫无意义。

更重要的是,句柄是绑定在进程上下文里的。进程A里的HANDLE 0x0000000C,和进程B里的HANDLE 0x0000000C,在内核句柄表里指向的可能是完全不同的内核对象,拥有完全不同的权限。

当你拿着这个HANDLE调用TerminateProcess时,内核做的事情不是“去执行终止动作”,而是拿着你的句柄去查表:

  • 这个句柄存在吗?不存在,返回错误。

  • 这个句柄指向的是进程对象吗?类型不对,返回错误。

  • 这个句柄在创建时,是否赋予了PROCESS_TERMINATE权限?没有,拒绝访问。

三关过完,内核才会真正解引用那个内部指针。

这种设计在当年付出了不小的代价——每一次通过HANDLE操作内核资源,都必须经过一次查表和权限硬校验,带来了一点点性能损耗。但是在工程上,它换来了一个极度可怕的优势:系统的强壮性与可演进性。

微软可以在Win95到Win11的三十年间,把内核里的EPROCESS结构体改得妈都不认识,添加无数个调试字段,修改无数次内存布局,而上层的Win32应用程序完全不需要重新编译。因为应用程序手里只有HANDLE,它永远触碰不到内核结构的真相。

这种“用间接性(Indirection)换取解耦与安全”的思路,后来的很多高并发和虚拟化系统都在沿用。

但是,如果只把HANDLE理解成“带权限的间接指针”,其实只理解了一半。

HANDLE能够支撑起整个Windows生态,最重要的另一个拼图,是NT内核强行抽离出的统一同步模型:WaitForSingleObject/WaitForMultipleObjects。

在Unix世界里,很多年来,同步机制都是碎片化的。你等一个文件可读用select/poll;你等一个子进程退出用waitpid;你等一个信号量用sem_wait。它们是完全不同的范式,很难优雅地组合在一起。

而在Windows里,所有内核对象在头头部都有一个共同的底层结构:DISPATCHER_HEADER。

不论是进程、线程、事件(Event)、定时器(Timer)、还是互斥量(Mutex),只要它们是内核对象,内部都有这个Header。这意味着,它们都可以处于两种状态之一:Signaled(有信号)或Nonsignaled(无信号)。

这就导致了一个极其优雅的工程结果:

应用层不需要关心这个HANDLE到底是一个耗时下载的网络套接字、一个正在运行的后台线程、还是一个等待触发的定时器。只要它是一个HANDLE,你就可以直接把它扔进WaitForMultipleObjects。

“当这三个线程结束、或者这个定时器超时、或者这个互斥量被释放,只要其中任意一个发生,就唤醒我。”

这种把所有异步和同步原语统一步骤的设计,在1990年代初的操作系统领域,是极其震撼的。它把复杂的多线程并发控制,收拢到了极少数几个统一的API上。

那这个设计是完美的吗?当然不是。

天下没有免费的午餐,HANDLE的代价同样深刻地影响了Windows的生态。

首先是资源泄漏的诊断成本极其高昂。在Unix上,fd泄露通常很容易定位,因为就那么几个文件。但在Windows上,因为一切皆可HANDLE,当一个大型程序运行几天出现“句柄泄漏”时,你面对的是几万个不知名的内核对象。你根本不知道这个leaked handle到底是个没关的事件,还是某个第三方SDK偷偷创建却忘了释放的线程句柄。

其次,句柄表变成了进程间通信的天然壁垒。因为HANDLE是强绑在进程私有句柄表里的,你想把一个句柄传给另一个进程使用,你不能直接发个整数过去。你必须调用极其繁琐的DuplicateHandle API,让内核在目标进程的句柄表里也拷贝一份槽位。这种设计极大地增加了进程间协同(IPC)的编写复杂度。

更有意思的是,近十年来,随着高性能网络和I/O时代的到来,传统基于HANDLE的同步机制也开始显现疲态。

WaitForMultipleObjects有一个写死在内核里的致命限制:最多只能同时等待64个句柄(MAXIMUM_WAIT_OBJECTS)。

当现代服务器需要处理数万个并发连接时,这种基于对象句柄的等待模型彻底崩塌了。微软不得不后来引入了IOCP(I/O完成端口),乃至近年来在Windows上推行类似io_uring的IORING机制,以此来绕过句柄检索的巨大开销。

现在回看历史,有时候挺有意思的。

Linux在经历了几十年的发展后,也遇到了同样的困境。比如:如何安全地管理进程?早期Linux依靠PID杀进程,但PID会重用。如果在你发信号的瞬间,目标进程刚好退出了,新进程用了同一个PID,你就会误杀一个完全无关的进程。

为了解决这个问题,Linux在内核5.1引入了pidfd_open——通过一个文件描述符来代表一个进程。

当Linux开始把进程、定时器(timerfd)、信号(signalfd)、甚至是事件(eventfd)全都封装成fd,并且在fd上附加各种anon_inode和权限检查时……

你仔细想想,这不就是换了个名字的HANDLE吗?

技术演进到最后,大路通天,大家终究会在同一个物理约束面前相遇。

Unix选择了“一切皆文件”,最后为了解决复杂对象的管理,把fd演变成了能力令牌;Windows选择了“一切皆对象”,通过HANDLE直接把能力令牌做成了底座,代价是承载了数十年的对象系统包袱。

没有哪一种是天生高贵的“优雅”,有的只是工程团队在特定历史时期,为了应对特定复杂度所做出的权衡和妥协。

本内容由作者授权发布,观点仅代表作者本人,不代表虎嗅立场。如对本稿件有异议或投诉,请联系 tougao@huxiu.com。

本文来自虎嗅,原文链接:https://www.huxiu.com/article/4881006.html?f=wyxwapp

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
特朗普要求打造的海军全新核动力“黄金舰队”,造价或高达2750亿美元,将配备高超音速武器、巡航导弹等

特朗普要求打造的海军全新核动力“黄金舰队”,造价或高达2750亿美元,将配备高超音速武器、巡航导弹等

每日经济新闻
2026-08-06 23:18:24
Lisa线下活动像纸片人,粉丝狂夸这种畸形审美,直言Lisa好薄一片

Lisa线下活动像纸片人,粉丝狂夸这种畸形审美,直言Lisa好薄一片

芊手若
2026-08-05 17:18:46
3年7300万!让库明加担心、懊悔的合同诞生了

3年7300万!让库明加担心、懊悔的合同诞生了

篮球大视野
2026-08-06 16:27:24
国米错失三大目标?引进右翼卫没有前置条件,转会钥匙却没变!

国米错失三大目标?引进右翼卫没有前置条件,转会钥匙却没变!

肥强侃球
2026-08-06 23:22:08
官方:江苏肯帝亚签下30岁前吉林中锋曾繁日

官方:江苏肯帝亚签下30岁前吉林中锋曾繁日

懂球帝
2026-08-06 13:55:05
多地“兰州拉面”改名“青海拉面”

多地“兰州拉面”改名“青海拉面”

界面新闻
2026-08-06 18:00:26
吞下联赛首败!山东男篮70‑81负广厦,对抗下命中率暴跌,过度依赖单核,篮板失守,李敬宇亟待解决诸多难题

吞下联赛首败!山东男篮70‑81负广厦,对抗下命中率暴跌,过度依赖单核,篮板失守,李敬宇亟待解决诸多难题

老周观体育
2026-08-06 23:47:38
猪八戒的资产留给私生子!?

猪八戒的资产留给私生子!?

八卦疯叔
2026-08-06 10:47:13
71万网红惊传离世!「曾涉毒又患忧郁」陈尸住家享年36岁

71万网红惊传离世!「曾涉毒又患忧郁」陈尸住家享年36岁

ETtoday星光云
2026-08-06 11:47:29
又一例基因编辑儿童死亡!与仇子龙事件高度相似,死亡案例都被隐瞒一年!IIT为何频频出事?

又一例基因编辑儿童死亡!与仇子龙事件高度相似,死亡案例都被隐瞒一年!IIT为何频频出事?

梅斯医学
2026-08-06 15:27:52
被打惨了,“野莓”的危机正在蔓延!!!

被打惨了,“野莓”的危机正在蔓延!!!

山河路口
2026-08-05 15:41:06
江青墓地简陋寒酸:看了碑文,就能明白李讷的苦心和无奈

江青墓地简陋寒酸:看了碑文,就能明白李讷的苦心和无奈

诗意世界
2025-05-21 09:00:02
李敏晚年坦言:若毛岸英没牺牲,贺子珍不会孤守上海半生

李敏晚年坦言:若毛岸英没牺牲,贺子珍不会孤守上海半生

夏至陌离殇
2026-07-30 22:44:51
连皇帝和亲爹都不用避讳了,你个竹知了算老几?

连皇帝和亲爹都不用避讳了,你个竹知了算老几?

基本常识
2026-08-04 10:58:06
FIFA官方宣布全力支持因凡蒂诺!不再容忍 采取一切措施保护名誉

FIFA官方宣布全力支持因凡蒂诺!不再容忍 采取一切措施保护名誉

念洲
2026-08-06 06:47:52
一个家庭最大的失败,不是穷,而是养出了一个没有敬畏的孩子

一个家庭最大的失败,不是穷,而是养出了一个没有敬畏的孩子

诺妈家有男宝娃
2026-08-06 17:24:02
威姆斯谈朱芳雨杜锋离队:广东必须要走这一步 相信他们会再次回归

威姆斯谈朱芳雨杜锋离队:广东必须要走这一步 相信他们会再次回归

狼叔评论
2026-08-06 17:00:07
【2026.8.5】吴签出狱了是真的吗?吴尊女儿准备进圈?《异人之下》还有后续?田曦薇现在是什么咖位?《御廷谣》现在很扑?

【2026.8.5】吴签出狱了是真的吗?吴尊女儿准备进圈?《异人之下》还有后续?田曦薇现在是什么咖位?《御廷谣》现在很扑?

娱乐真爆姐
2026-08-06 00:58:53
油价大跌!一夜失控,8月6日全国92,95汽油“预跌390元/吨”,今天降幅“再多40元/吨”,下次8月14日调价“或大降”!

油价大跌!一夜失控,8月6日全国92,95汽油“预跌390元/吨”,今天降幅“再多40元/吨”,下次8月14日调价“或大降”!

猪友巴巴
2026-08-06 09:12:40
“这才是政审的意义!”女子考公上岸后,被高中欺负过的同学举报

“这才是政审的意义!”女子考公上岸后,被高中欺负过的同学举报

妍妍教育日记
2026-07-17 08:25:14
2026-08-07 00:43:00
虎嗅APP incentive-icons
虎嗅APP
个性化商业资讯与观点交流平台
27136文章数 687969关注度
往期回顾 全部

科技要闻

凌晨谷歌AI地震!4位大牛离职 CEO退居二线

头条要闻

地面打不穿"空战"打不停 普京高调"换将"或直面消耗战

头条要闻

地面打不穿"空战"打不停 普京高调"换将"或直面消耗战

体育要闻

曝维尼修斯与皇马续约4年 年薪2400万欧

娱乐要闻

周杰伦私生活被扒,澳门传闻水落石出

财经要闻

"杭州六小龙"群核科技物理AI故事有水分?

汽车要闻

上汽通用再签20年:合资2.0时代,玩法变了

态度原创

家居
房产
手机
时尚
教育

家居要闻

2026建博会(广州) 公装联探展交流活动

房产要闻

重磅调规!海口府城板块,要新增一所完全中学!

手机要闻

荣耀MagicOS 11内测招募,首发琉光架构+全新蜂鸟架构

1.7亿女性,确诊PMOS

教育要闻

zero hour居然不是零点?关键时刻又弄错!

无障碍浏览 进入关怀版