被遗忘的旧消息:LB_INITSTORAGEForgotten message from the past: LB_INITSTORAGE
文章回顾了 Windows 列表框控件中的一个旧特性 LB_INITSTORAGE,该机制用于预分配内存以优化性能。若不启用此标志,动态添加大量项会导致二次时间复杂度行为,显著降低响应速度。Raymond Chen 解释了这一设计背后的原理,强调在现代系统中合理使用内存预分配的重要性。
Raymond Chen
经典的 Win32 列表框控件允许你在添加大量项之前预先分配内存。官方文档建议在向列表框中添加超过 100 个项时进行此操作¹。那么这里具体预分配的是什么?
列表框内部将项维护为一个结构体数组和一个独立的字符串内存池。LB_INITSTORAGE 的作用是通知列表框控件为这两个部分预分配内存:第一个内存块要足够大,以便至少能容纳 wParam 个项;第二个内存块则扩展至可容纳额外的 lParam 字节字符串数据。
存储一个字符串所需的字节数包括空终止符,因此一个 12 字符的 Unicode 字符串需要 (12 + 1) × 2 = 26 字节。例如,如果你希望总共包含 100 个平均长度为 10 字符的 Unicode 字符串,建议将字符串内存池扩展 100 × (10 + 1) × 2 = 2200 字节。此时调用 LB_INITSTORAGE 即可实现。
SendMessage(hwndLB, LB_INITSTORAGE, 100, 100 * (10 + 1) * sizeof(TCHAR));通过预分配内存,可以避免在每次添加新项时缓冲区都需要扩容所导致的二次内存分配行为²。
¹ 个人而言,我认为从可用性角度看,列表框中放置 100 个项实在太多了。如果真有这么多选项,我建议使用自动补全输入框(auto-suggest box),让用户只需输入部分关键词就能缩小搜索范围,而不必被迫翻页滚动查找目标项。
² 但需注意,二次性能问题并未完全避免。因为内部实际上是将多个并行数组打包在一起,所以添加一项时,必须移动后续所有并行数组中的项,为新项腾出第一个数组中的位置。这也是不建议在列表框中放置大量项的另一个原因。
分类
主题
作者
Raymond 参与 Windows 系统演进已超过 30 年。2003 年,他创建了一个名为 The Old New Thing 的网站,其受欢迎程度远超他的想象,至今仍让他感到些许不安。该网站催生了一本同名书籍《The Old New Thing》(Addison Wesley, 2007)。他偶尔会在 Windows Dev Docs 的 Twitter 账号上出现,讲述一些毫无实用价值的故事。
需要完整排版与评论请前往来源站点阅读。