书籍:《Visual C++ 2017从入门到精通》的4.2 按钮控件
环境:visual studio 2022
内容:[例 4.2]制作图片按钮
说明:以上内容大部分来自腾讯元宝。
在 Windows 内存管理中,当使用 GlobalAlloc(GMEM_FIXED, len)
分配内存时,不需要执行 GlobalLock
操作。以下是详细分析:
核心原因
-
内存句柄即指针
GMEM_FIXED
分配的内存块地址直接由句柄HGLOBAL
表示,调用GlobalLock(m_hMem)
会返回与句柄相同的指针值(即m_hMem
本身)。- 示例:
HGLOBAL hMem = GlobalAlloc(GMEM_FIXED, 1024); BYTE* pData = (BYTE*)GlobalLock(hMem); // pData == hMem
-
锁定机制的适用场景
- 锁定操作主要用于 可移动内存(
GMEM_MOVEABLE
),防止系统在内存压缩时移动或释放内存块。 - 固定内存块的位置在分配后永久不变,无需通过锁定来保证访问安全。
- 锁定操作主要用于 可移动内存(
调用 GlobalLock
的潜在影响
虽然技术上可以调用,但会产生以下问题:
-
冗余操作
- 锁定计数器会增加,但固定内存的物理地址不会改变,解锁操作(
GlobalUnlock
)也不会释放内存。
- 锁定计数器会增加,但固定内存的物理地址不会改变,解锁操作(
-
API 兼容性风险
- 某些旧版 API 可能依赖锁定计数器状态,但现代开发中已无此必要。
正确使用示例
// 分配固定内存(无需锁定)
HGLOBAL hMem = GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, 1024);
BYTE* pData = (BYTE*)hMem; // 直接使用句柄作为指针
// 写入数据
memcpy(pData, sourceData, 1024);
// 释放内存(无需解锁)
GlobalFree(hMem);
对比:GMEM_MOVEABLE
的强制锁定
对于可移动内存,必须通过 GlobalLock
获取有效指针:
HGLOBAL hMoveableMem = GlobalAlloc(GMEM_MOVEABLE, 1024);
BYTE* pData = (BYTE*)GlobalLock(hMoveableMem); // 必须锁定
// ... 使用内存 ...
GlobalUnlock(hMoveableMem); // 解锁后内存可能被系统移动
GlobalFree(hMoveableMem);
总结
分配标志 | 是否需要 GlobalLock | 原因 |
---|---|---|
GMEM_FIXED | 否 | 句柄即指针,内存位置固定 |
GMEM_MOVEABLE | 是 | 需锁定以获取稳定地址,防止内存移动 |
建议:在 GMEM_FIXED
分配时,直接使用句柄作为指针,避免冗余的锁定/解锁操作以提高性能。