C ++一些Stack问题

时间:2011-07-01 22:53:31

标签: c++ stack

首先我要说的是,我已阅读this tutorial并已阅读this question。我的问题是:

  1. 筹码有多大?是吗 处理器/架构/编译器 依赖?

  2. 有没有办法确切知道如何 我有很多记忆 函数/类堆栈和多少 目前正在使用 避免溢出?

  3. 使用现代编译器(比如gcc 4.5) 在现代计算机上(比如6 GB ram), 我需要担心堆栈吗? 溢出或是它的一部分 过去?

  4. 是实际的堆栈内存 物理上在RAM或CPU缓存上?

  5. 堆栈内存快多少 访问和读取与堆相比 访问和阅读?我意识到了 时间是PC特定的,所以比例是 够了。

  6. 我读过这是不可取的 分配大变量/对象 堆。太大了多少钱? This question here得到答案 win32中的一个线程为1MB。怎么样 关于Linux amd64中的一个帖子?

  7. 如果已经提出并回答了这些问题我很抱歉,欢迎任何链接!

3 个答案:

答案 0 :(得分:8)

  1. 是的,堆栈大小的限制会有所不同,但如果你关心你可能可能做错了什么。
  2. 一般情况下,您无法获得有关程序可用内存量的信息。即使您可以获得此类信息,在使用之前通常也会过时。
  3. 如果您共享跨线程数据的访问权限,那么您通常需要序列化访问权限,除非它们是严格只读的。
  4. 您可以将堆栈分配对象的地址传递给另一个线程,在这种情况下,您(再次)必须序列化,除非该访问是严格只读的。
  5. 即使在具有大量内存的现代机器上,您当然可以溢出堆栈。堆栈通常仅限于总内存的相当小的一部分(例如,4 MB)。
  6. 堆栈被分配为系统内存,但通常使用得足以使任何给定时间至少首页或两个通常位于缓存中。
  7. 作为堆栈与堆的一部分对访问速度没有直接影响 - 两者通常位于相同的内存芯片中,甚至通常位于同一内存芯片中的不同地址。主要区别在于堆栈通常是连续的并且使用频繁,前几页几乎总是在缓存中。基于堆的内存通常是碎片化的,因此需要更多的机会来获取不在缓存中的数据。
  8. 对于您应该在堆栈上分配的对象的最大大小,几乎没有变化。即使堆栈可以更大,也没有理由在那里分配大型对象。
  9. 避免C ++内存泄漏的主要方法是RAII(AKA SBRM,基于堆栈的资源管理)。
  10. 智能指针本身就是一个很大的主题,Boost提供了几种。根据我的经验,集合会产生更大的差异,但基本思想在很大程度上都是相同的:减轻程序员跟踪特定对象可以使用或应该被释放的每种情况。

答案 1 :(得分:3)

  

1.筹码有多大?是处理器/体系结构/编译器依赖吗?

堆栈的大小受平台内存量操作系统分配给进程的内存量的限制。

  

2.有没有办法确切知道我的函数/类堆栈有多少内存可用,以及当前使用多少内存以避免溢出?

没有用于确定可用内存量的C或C ++工具。可能存在特定于平台的功能。通常,大多数程序尝试分配内存,然后为分配失败时提出解决方案。

  

3.在现代计算机上使用现代编译器(例如gcc 4.5)(比如6 GB ram),我是否需要担心堆栈溢出或者它是否已成为过去?

根据程序的设计,可能会发生堆栈溢出。无论内存量多少,递归都是耗尽堆栈的一个很好的例子。

  

4.实际堆栈内存是物理上在RAM上还是在CPU缓存上?

依赖于平台。某些CPU可以使用堆栈上的本地变量加载其缓存。关于此主题的各种场景。未在语言规范中定义。

  

5.与堆访问和读取相比,堆栈内存访问和读取的速度要快得多吗?   我意识到时间是PC特定的,所以比例就足够了。

通常情况下,速度没有区别。取决于平台如何组织其内存(物理上)以及如何布置可执行文件的内存。堆或堆栈可以驻留在串行存取存储器芯片(慢速方法)中,甚至存在于闪存芯片上。未在语言规范中指定。

  

6.我已经读过,不建议在堆栈上分配大变量/对象。太大了多少钱?这个问题给出了win32中一个主题的1MB的答案。 Linux amd64中的一个线程怎么样?

最好的建议是根据需要分配本地小变量(a.k.a. via stack)。巨大的项目要么从动态内存(a.k.a. heap)中分配,要么从某种全局(静态本地到函数或本地到翻译单元甚至全局变量)分配。如果在编译时已知大小,请使用全局类型分配。在运行时可能会更改大小时使用动态内存。

堆栈还包含有关函数地址的信息。这是不在本地分配大量对象的一个​​主要原因。某些编译器对堆栈的限制小于堆或全局变量。前提是嵌套函数调用比大数据数组或缓冲区需要更少的内存。

请记住,在切换线程或任务时,操作系统需要在某处保存状态。操作系统可能有不同的规则来保存堆栈内存与其他类型。

答案 2 :(得分:2)

1-2:在某些嵌入式CPU上,堆栈可能限制在几千字节;在某些机器上,它可能扩展到千兆字节。在某种程度上,由于某些平台能够在达到极限时扩展堆栈,因此没有独立于平台的方法来了解堆栈的大小。这种行动的成功并不总能提前预测。

3:在没有锁,互斥锁或其他此类设备的情况下,几乎同时写入或在一个线程中写入几乎与另一个线程中的读取同时发生的影响在很大程度上是不可预测的。可以假定某些事情(例如,如果一个线程读取堆存储的'int'而另一个线程将其从4更改为5,则第一个线程可能看到4或者它可能看到5;在大多数平台上,它将得到保证不要看27)。

4:某些平台在线程之间共享堆栈地址空间;别人不这样做。但是,将指针传递给堆栈上的东西通常是一个坏主意,因为接收指针的外部线程无法确保目标在范围内并且不会超出范围。

5:通常人们不需要担心任何编写的例程中的堆栈空间,以便将递归限制在合理的水平。但是,人们需要担心有缺陷的数据结构导致无限递归的可能性,无论它有多大,都会消除任何堆栈。人们还应该注意到令人讨厌的输入的可能性,这将导致比预期更大的堆栈深度。例如,使用递归下降解析器的编译器可能会阻塞一个包含十亿次重复序列“1+(”)的文件。即使机器有一堆堆栈空间,如果每个嵌套子表达式使用64个字节堆栈,前面提到的三个gig文件可以杀死它。

6:堆栈通常存储在RAM和/或缓存中;最近访问的部分通常位于缓存中,而最近访问较少的部分将位于主存储器中。代码,堆和静态存储区域也是如此。

7:这是非常依赖系统的;通常,在堆上“查找”某些内容将花费与访问堆栈上的一些内容相同的时间,但在许多情况下,对同一堆对象的不同部分进行多次访问可以与访问堆栈对象一样快。