据我所知,当操作系统创建线程时,每个线程都会获得一个不同的堆栈。我想知道每个线程是否也有一个与自身不同的堆?
答案 0 :(得分:120)
没有。所有线程共享一个公共堆。
每个thread has a private stack,可以快速添加和删除项目。这使得基于堆栈的内存很快,但是如果你使用太多的堆栈内存,就像在无限递归中那样,你将获得堆栈溢出。
由于所有线程共享同一个堆,因此必须同步对allocator / deallocator的访问。有许多方法和库可以避免allocator contention。
某些语言允许您创建私有内存池或单个堆,您可以将其分配给单个线程。
答案 1 :(得分:9)
答案 2 :(得分:5)
取决于操作系统。 Windows和unices上的标准c运行时使用跨线程的共享堆。这意味着锁定每个malloc / free。
在Symbian上,每个线程都有自己的堆,尽管线程可以共享指向任何堆中分配的数据的指针。在我看来,Symbian的设计更好,因为它不仅消除了在alloc / free期间锁定的需要,而且还鼓励在线程之间清晰地指定数据所有权。同样在这种情况下,当一个线程死亡时,它会获取它随之分配的所有对象 - 即它不会泄漏它已分配的对象,这是具有受限内存的移动设备中的重要属性。
Erlang也遵循类似的设计,其中“进程”充当垃圾收集的单元。所有数据都是通过复制在进程之间传递的,除了参考计数的二进制blob(我认为)。
答案 3 :(得分:3)
每个线程都有自己的堆栈和调用堆栈。
每个线程共享同一个堆。
答案 4 :(得分:2)
这取决于你说“堆”时的确切含义。
所有线程共享地址空间,因此可以从所有线程访问堆分配的对象。从技术上讲,堆栈在这个意义上也是共享的,即没有什么能阻止你访问其他线程的堆栈(尽管这样做几乎没有任何意义)。
另一方面,有用于分配内存的堆结构。这就是堆内存分配的所有簿记都已完成的地方。这些结构经过精心组织,以最大限度地减少线程之间的争用 - 因此一些线程可能共享堆结构(竞技场),而某些线程可能使用不同的竞技场。 有关详细信息的详细说明,请参阅以下主题:How does malloc work in a multithreaded environment?
答案 5 :(得分:1)
通常,线程共享堆和其他资源,但是有类似线程的结构却没有。在这些类似线程的结构中,有Erlang的轻量级进程和UNIX的完全进程(通过调用fork()
创建)。您可能还在处理多机并发,在这种情况下,您的线程间通信选项会受到更多限制。
答案 6 :(得分:1)
一般来说,所有线程都使用相同的地址空间,因此通常只有一个堆。
然而,它可能会有点复杂。您可能正在寻找Thread Local Storage(TLS),但它仅存储单个值。
特定于Windows的: 可以使用TlsAlloc分配TLS空间,并使用TlsFree(概述here)释放。同样,它不是堆,只是DWORD。
奇怪的是,Windows支持每个进程多个Heaps。可以在TLS中存储Heap的句柄。然后你会有类似“线程局部堆”的东西。但是,只是其他线程不知道句柄,它们仍然可以使用指针访问其内存,因为它仍然是相同的地址空间。
编辑:一些内存分配器(特别是FreeBSD上的jemalloc)使用TLS为线程分配“arenas”。这样做是为了通过减少同步开销来优化多个核的分配。
答案 7 :(得分:1)
在FreeRTOS操作系统上,任务(线程)共享同一个堆,但每个堆都有自己的堆栈。这在处理低功耗低RAM架构时非常方便,因为同一个内存池可以被多个线程访问/共享,但这带来了一个小问题,开发人员需要记住一个同步malloc的机制需要free,这就是为什么在堆上分配或释放内存时需要使用某种类型的进程同步/锁定,例如信号量或互斥量。