在非递归函数中,通常可以在堆栈上放置大数据类型吗?
一个方便的地方是需要清理的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中,我认为这不是很整洁吗?
答案 0 :(得分:4)
在主流PC上的单线程应用程序中,没有太多需要关注:这里有几个KiB,那里有几个Kib;最终,也许,你在堆栈上达到MiB或者两个。堆栈自动增长,应用程序的成本最低。
如果您正在处理多线程应用程序,则情况会发生变化。每个线程都有自己的堆栈,并且(据我所知),线程启动时堆栈大小是固定的。如果您开始使用大型局部变量来混乱线程的堆栈,则可能会占用所有堆栈并耗尽空间。因此,最好为较大的对象使用动态内存分配,以避免遇到此类问题。既然你也可以为单线程应用程序做动态分配,如果程序有可能演变成多线程程序,那么你可能应该从一开始就使用动态分配。请注意,动态分配比堆栈上的自动分配慢。
如果您正在处理内存有限的系统,那么您希望避免创建大型对象,句点。至少,您必须担心任何时候存在多少,并确保尽快释放它们。
答案 1 :(得分:1)
“这取决于。”在机器上,设备,块的大小,以及堆栈已经在你下面的大小。
在你的例子中,非递归函数中的~9k块几乎总是没问题。 (这里的例外情况是小型嵌入式设备,或者如果你有很多其他功能在同一个堆栈上做同样的事情。)
作为纯粹的个人经验法则,我通常不会将堆栈用于普通应用程序级代码中高于几K的任何缓冲区。如果您正在进行数据包传输,就像在您的示例中一样,并且它处于循环中,您可能会看到每次执行动态分配时的性能开销,因此您要么将其保留在堆栈中,请在某处保留静态缓冲区,或者某种可重复使用的缓冲池。