原子表是系统定义的表,用于存储字符串和相应的标识符。
Atom 表中放置一个字符串(称为 原子名称),并接收一个 16 位整数(称为 atom),该整数可用于访问该字符串。
系统提供许多原子表。 每个原子表都有不同的用途。
例如,Dynamic Data Exchange (DDE) 应用程序使用 全局 atom 表 与其他应用程序共享item-name和topic-name字符串。
DDE 应用程序将全局原子传递给其合作伙伴应用程序,而不是传递实际字符串。
伙伴使用原子从 atom 表中获取字符串。应用程序可以使用本地 Atom 表来存储其自己的项名称关联。
系统使用应用程序无法直接访问的 Atom 表。 但是,应用程序在调用各种函数时使用这些原子。
例如,注册的剪贴板格式存储在系统使用的内部 Atom 表中。
应用程序使用 注册剪板 函数将 atom 添加到此 Atom 表。
此外,已注册的类存储在系统使用的内部原子表中。
应用程序使用 注册窗类 或 注册窗体 函数将 atom 添加到此 Atom 表。
全局 Atom 表
全局 Atom 表可供所有应用程序使用。
当应用程序在全局 Atom 表中放置字符串时,系统会生成一个在整个系统中唯一的原子。
具有 atom 的任何应用程序都可以通过查询全局 atom 表来获取它标识的字符串。
定义用于与其他应用程序共享数据的专用 DDE 数据格式的应用程序应将格式名称放在全局 Atom 表中。
此技术可防止与系统或其他应用程序定义的格式的名称发生冲突,并使标识符 (原子) 其他应用程序可用的消息或格式。
用户 Atom 表
除了全局 Atom 表,用户 Atom 表是另一个系统 Atom 表,也是在所有进程之间共享的。
用户原子表用于 win32k 内部的少量方案;例如,Windows 模块名称、win32k 中的已知字符串、OLE 格式等。
尽管应用程序不直接与用户 Atom 表交互,但它们会调用多个 API(如 注册窗类 注册消息 和 注册剪板),
这些 API 可将条目添加到用户 Atom 表。 添加的 注册窗类 条目可由 注销窗类 删除。
但是,在会话结束之前,不会删除 由 注册消息 和 注册剪板 添加的条目。
如果用户 Atom 表没有更多的空间,并且传入的字符串不在表中,则调用将失败。
Atom 表大小
许多关键 API(包括 创建窗口)依赖于用户原子。
因此,用户 Atom 表中的空间耗尽将导致严重问题:例如,所有应用程序都可能无法启动。
下面是一些建议,可确保应用程序有效地利用 Atom 表,并保留应用程序和系统的可靠性和性能:
1。应限制应用对用户 Atom 表的使用。
使用 API(如 注册窗类、注册消息 或 注册剪板 )存储唯一字符串会占用用户 Atom 表中的空间,
其他应用全局使用该空间来使用字符串注册窗口类。
如果可能,应使用 添加名单/删除名单 将字符串存储在本地 Atom 表中,或者使用 添全名单/删全名单 (如果需要原子跨进程)。
2。如果担心应用程序会导致用户 Atom 表问题,
可以通过连接内核调试器并在调用UserAddAtomEx (bae1 win32kbase!UserAddAtomEx /p "kc10;g")
时进入进程来调查根本原因。
在调用堆栈上查找 user32! ,以查看正在调用哪个 API。
该方法类似于识别全局原子表泄漏中介绍 的全局原子表问题检测。 转储用户 Atom 表内容的另一种方法是
在从 0xC000 到 0xFFFF 的可能原子范围内调用 剪切板名 。
如果在应用程序运行时,总原子计数稳步上升,或者在关闭应用时未返回到基线,则存在问题。
本地 Atom 表
应用程序可以使用本地 Atom 表有效地管理仅在应用程序中使用的大量字符串。
这些字符串和关联的原子仅适用于创建表的应用程序。
许多结构中需要相同字符串的应用程序可以通过使用本地 Atom 表来减少内存使用量。
应用程序可以将字符串放置在 atom 表中,并将生成的原子包含在结构中,
而不是将字符串复制到每个结构中。 这样,字符串在内存中只出现一次,但可以在应用程序中多次使用。
在搜索特定字符串时,应用程序还可以使用本地 Atom 表来节省时间。
若要执行搜索,应用程序只需将搜索字符串放在 atom 表中,并将生成的原子与相关结构中的原子进行比较。
比较原子通常比比较字符串快。Atom 表作为哈希表实现。
默认情况下,本地 Atom 表对其哈希表使用 37 个存储桶。
但是,可以通过调用 初始名单 函数更改使用的存储桶数。
但是,如果应用程序调用 初始名单,则必须在调用任何其他 Atom 管理功能之前执行此操作。