我应该避免在堆栈上放置大型物体吗?

时间:2011-12-26 03:25:00

标签: c

在非递归函数中,通常可以在堆栈上放置大数据类型吗?

一个方便的地方是需要清理的C函数。

e.g。     我有一个C函数,允许我像这样读/写任意数据包。

int do_something()
{
  char buf[9000];
  struct ot_packet_t p;

  pkt_init(&p);
  pkt_set_type(&p, "WDAT");
  pkt_write_uint32(&p, some_var);
  pkt_write_data(&p, some_data, some_len);

  // other stuff...
  // if need to early exit... buf & p cleaned up.  An RAII approach.

  send_packet(buf, pkt_get_length(&p));
}

我用C ++标记了这个问题,并且它也适用于C ++。 虽然至少在C ++上,我通常会使用auto_ptr来清理堆上分配的较大对象。在C中,我认为这不是很整洁吗?

2 个答案:

答案 0 :(得分:4)

在主流PC上的单线程应用程序中,没有太多需要关注:这里有几个KiB,那里有几个Kib;最终,也许,你在堆栈上达到MiB或者两个。堆栈自动增长,应用程序的成本最低。

如果您正在处理多线程应用程序,则情况会发生变化。每个线程都有自己的堆栈,并且(据我所知),线程启动时堆栈大小是固定的。如果您开始使用大型局部变量来混乱线程的堆栈,则可能会占用所有堆栈并耗尽空间。因此,最好为较大的对象使用动态内存分配,以避免遇到此类问题。既然你也可以为单线程应用程序做动态分配,如果程序有可能演变成多线程程序,那么你可能应该从一开始就使用动态分配。请注意,动态分配比堆栈上的自动分配慢。

如果您正在处理内存有限的系统,那么您希望避免创建大型对象,句点。至少,您必须担心任何时候存在多少,并确保尽快释放它们。

答案 1 :(得分:1)

“这取决于。”在机器上,设备,块的大小,以及堆栈已经在你下面的大小。

在你的例子中,非递归函数中的~9k块几乎总是没问题。 (这里的例外情况是小型嵌入式设备,或者如果你有很多其他功能在同一个堆栈上做同样的事情。)

作为纯粹的个人经验法则,我通常不会将堆栈用于普通应用程序级代码中高于几K的任何缓冲区。如果您正在进行数据包传输,就像在您的示例中一样,并且它处于循环中,您可能会看到每次执行动态分配时的性能开销,因此您要么将其保留在堆栈中,请在某处保留静态缓冲区,或者某种可重复使用的缓冲池。