代码改变世界

多线程中 堆和栈的区别

2014-11-17 09:26  youxin  阅读(12558)  评论(0编辑  收藏  举报
很多现代操作系统中,一个进程的(虚)地址空间大小为4G,分为系统空间和用户空间两部分,系统空间为所有进程共享,而用户空间是独立的,一般WINDOWS进程的用户空间为2G。
  一个进程中的所有线程共享该进程的地址空间,但它们有各自独立的(私有的)栈(stack),Windows线程的缺省堆栈大小为1M。堆(heap)的分配与栈有所不同,一般是一个进程有一个C运行时堆,这个堆为本进程中所有线程共享,Windows进程还有所谓进程默认堆,用户也可以创建自己的堆。
堆: 是大家共有的空间,分全局堆和局部堆。全局堆就是所有没有分配的空间,局部堆就是用户分配的空间。堆在操作系统对进程初始化的时候分配,运行过程中也可以向系统要额外的堆,但是记得用完了要还给操作系统,要不然就是内存泄漏。
 
栈:是个线程独有的,保存其运行状态和局部自动变量的。栈在线程开始的时候初始化,每个线程的栈互相独立,因此,栈是 thread safe的操作系统在切换线程的时候会自动的切换栈,就是切换 SS/ESP寄存器。栈空间不需要在高级语言里面显式的分配和释放。

参考资料: 进程线程与栈 堆的关系(转)

一篇文章:

最初涉及多线程程序涉及的时候经常会出现一些令人难以思议的事情,用堆和栈分配一个变量可能在以后的执行中产生意想不到的结果,而这个结果的表现就是内存的非法被访问,导致内存的内容被更改。

   理解这个现象的两个基本概念是:在一个进程的线程共享堆区,而进程中的线程各自维持自己堆栈。

另一运行机制就是如果声明一个成员变量 如 char Name[200],随着这段代码调用的结束,Name在栈区的地址被释放,而如果是 char * Name = new char[200]; 情况则完全不同,除非显示调用delete否则 Name指向的地址不会被释放。

   理解了线程对 堆栈 的可见性,和内存管理机制就能推测出笔者伊始提出的现象。

   用一个 实例来深入理解这种机制。

   在线程 1 中,

   A ()

   {

        B();

        C();

   }

   B()

   {

        栈 or 堆分配变量 V;

        将V的地址插入 公共队列;

   }

   线程 2 中:

   D()

   {

       while(1)

       {

           处理公共队列;

       }

   }

  在B中如果用栈区 即采用临时变量的机制分配声明V和堆区,而者的结果是不同的。如果用栈区,如果变量地址为Am1-Am2这么大,退出B调用时候这段地址被释放,C函数可能将这段内存改写;这样当D执行的时候,从内存Am1-Am2中读取的内容就是被改过的了。

  而如果用New(堆)分配,则不会出现那样的情况,因为没有显示对用delete并且堆对于线程共享,即2线程可以看到1线程在堆里分配的东西,所以不会发生误写。

http://blog.sina.com.cn/s/blog_5c4aa6bc0100gdbm.html

更多:http://blog.csdn.net/gykimo/article/details/9132157