You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

32位程序开启大量线程时malloc提前返回NULL的问题咨询

问题1:为什么程序无法用到2GB内存就触发内存不足?

这本质是32位进程虚拟地址空间碎片化导致的,和物理内存占用没有直接关系:

  • 32位Windows进程默认用户态虚拟地址空间总大小仅为2GB,所有内存分配(包括堆内存、线程栈、模块映射等)都需要从这个地址空间里分配连续的地址块。
  • 调用CreateThread且第二个参数传0时,Windows会为每个线程默认保留1MB的连续虚拟地址空间作为线程栈(哪怕实际提交的物理内存只有几KB,虚拟地址空间是预先占住的),同时还会为TEB(线程环境块)等结构分配地址空间。
  • 你的代码逻辑是「创建1个线程 → malloc约128KB内存」循环执行,相当于在2GB的虚拟地址空间里,每隔一段就插入一个1MB的保留块,直接把原本连续的地址空间切割成了大量小于128KB的碎片。等到后续malloc需要128KB连续地址时,虽然总空闲虚拟地址还有很多,但没有符合大小的连续块,就会返回NULL,此时物理内存占用看起来还很低。
    你的业务场景里创建800个线程就触发问题也符合这个逻辑:800个线程就占了至少800MB的虚拟地址空间作为栈,再加上地址切割带来的碎片,剩下的连续地址块自然不够用。

问题2:创建大量线程的操作是否会导致内存泄漏?

存在两处资源泄漏:

  • 线程内核对象泄漏:CreateThread会返回一个线程内核对象的句柄,内核对象的引用计数默认是1,你没有调用CloseHandle关闭这个句柄的话,哪怕线程执行结束退出,内核对象占用的内核态内存也不会被释放,会一直存在直到进程退出。
  • 虚拟地址空间泄漏:在你示例代码的场景中,线程函数调用了Sleep(100000),在malloc失败时所有线程都还没有退出,每个线程占有的1MB栈虚拟地址空间、TEB占用的空间都不会被释放,相当于这部分地址空间被持续占用。
    如果你的业务代码也没有关闭线程句柄、也没有等待线程退出回收资源,确实会存在持续的资源泄漏。

内容的提问来源于stack exchange,提问作者phibao37

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 18:06:03