为什么线程共享堆空间?

每个线程都有自己的堆栈,但它们共享一个公共堆。

每个人都清楚堆栈是针对本地/方法变量和堆的,例如/类变量。

在线程之间共享堆有什么好处。

有几个线程同时运行,因此共享内存可能会导致并发修改,互斥等开销问题。 堆中的线程共享哪些内容。

为什么会这样? 为什么不让每个线程拥有自己的堆呢? 任何人都可以提供一个真实世界的例子,线程如何利用共享内存?

如果要将数据从一个线程传递到另一个线程,您会怎么做? (如果你从未这样做过,你将编写单独的程序,而不是一个multithreading程序。)有两种主要方法:

  • 您认为理所当然的方法是共享内存 :除了具有特定于线程的强大理由的数据(例如堆栈)之外,所有线程都可以访问所有数据。 基本上,有一个共享堆。 这为您提供了速度 :每当线程更改某些数据时,其他线程都可以看到它。 (限制:如果线程在不同的处理器上执行,则情况并非如此:程序员需要特别努力地正确高效地使用共享内存。)大多数主要的命令式语言,特别是Java和C#,都支持这种模式。

    每个线程可以有一个堆,还有一个共享堆。 这要求程序员决定将哪些数据放在哪里,并且通常与现有的编程语言不能很好地融合。

  • 双重方法是消息传递 :每个线程都有自己的数据空间; 当一个线程想要与另一个线程通信时,它需要显式地向另一个线程发送一条消息,以便将数据从发送方的堆中复制到接收方的堆中。 在此设置中,许多社区更喜欢调用线程进程。 这给了你安全 :因为一个线程无法随心所欲地覆盖其他线程的内存,所以可以避免很多错误。 另一个好处是分发 :您可以让您的线程在不同的机器上运行,而无需更改程序中的单行。 您可以找到大多数语言的消息传递库,但集成往往不太好。 理解消息传递的好语言是Erlang和JoCaml 。

    事实上,消息传递环境通常使用场景后面的共享内存,至少只要线程在同一台机器/处理器上运行。 由于将消息从一个线程传递到另一个线程,因此节省了大量时间和内存,因此不需要复制数据。 但由于共享内存不会暴露给程序员,因此其固有的复杂性仅限于语言/库实现。

因为否则它们就是进程。 这就是线程的全部思想,共享内存。

进程不会 – 通常 – 共享堆空间。 有API允许这样做,但默认是进程是独立的

线程共享堆空间。

这就是“实用的想法” – 两种使用内存的方式 – 共享和不共享。

在许多语言/运行时中,堆栈(以及其他)用于保持函数/方法参数和变量。 如果线程共享一个堆栈,事情会变得非常混乱。

 void MyFunc(int a) // Stored on the stack { int b; // Stored on the stack } 

完成对“MyFunc”的调用后,将弹出堆叠,并且堆栈中不再有a和b。 因为线程不共享堆栈,所以变量a和b没有线程问题。

由于堆栈的性质(推/弹),它不适合在函数调用中保持“长期”状态或共享状态。 喜欢这个:

 int globalValue; // stored on the heap void Foo() { int b = globalValue; // Gets the current value of globalValue globalValue = 10; } void Bar() // Stored on the stack { int b = globalValue; // Gets the current value of globalValue globalValue = 20; } void main() { globalValue = 0; Foo(); // globalValue is now 10 Bar(); // globalValue is now 20 } 

堆只是动态分配的堆栈外的所有内存。 由于操作系统提供单个地址空间,因此很明显,根据定义,堆由进程中的所有线程共享。 至于为什么不共享堆栈,那是因为执行线程必须有自己的堆栈才能管理其调用树(例如,它包含有关离开函数时要执行的操作的信息!)。

现在你可以编写一个内存管理器,根据调用线程从地址空间的不同区域分配数据,但是其他线程仍然可以看到那些数据(就像你以某种方式泄漏指向线程上某些东西的指针一样)堆栈到另一个线程,其他线程可以读取它,尽管这是一个可怕的想法)

问题是拥有本地堆会增加非常小的价值的复杂性。

有一个很小的性能优势,TLAB(线程本地分配缓冲区)可以很好地处理这个问题,它可以透明地为您提供最大的优势。

在multithreading应用程序中,每个线程都有自己的堆栈,但将共享同一个堆。 这就是为什么应该在代码中注意避免堆空间中的任何并发访问问题。 堆栈是线程安全的(每个线程都有自己的堆栈)但堆不是线程安全的,除非通过代码保护同步。

那是因为线程的想法是“分享一切”。 当然,有一些你无法分享的东西,比如处理器上下文和堆栈,但其他一切都是共享的。