在堆上分配内存还是传递工作内存? [关闭]

Posted

技术标签:

【中文标题】在堆上分配内存还是传递工作内存? [关闭]【英文标题】:Allocating memory on heap or passing work memory? [closed] 【发布时间】:2015-08-21 05:32:14 【问题描述】:

函数需要额外内存的情况相对经常发生。

在旧代码中,我经常遇到额外的空间必须由调用者提供并作为工作数组传递给函数。我想这给调用函数留下了更多的灵活性,并可能提高性能。

另一方面,分配内存保证了内存实际可用,也简化了接口。

是否有处理这些情况的最佳做法?

【问题讨论】:

调用者如何知道被调用者需要多少空间来完成它的工作?您的第一个案例似乎是糟糕的软件工程。 “你是一个足够大的代码块,你应该拥有自己的功能,但现在我要把你的实现与我决定给你的内存量联系起来”。投票结束主要基于意见。 您是否自带座位上车?想到外部内存分配的唯一合理原因是函数输出...... @John3136 我同意你的观点,这感觉像是糟糕的软件工程,但如果你有一个经常调用的函数并且需要一个大小为 n 的额外数组,其中 n 在运行时已知,你可以避免每次调用函数时分配内存。 【参考方案1】:

在 C 代码中,通常让调用者处理内存分配,例如字符串。问题是被调用的函数不知道它实际可以使用多少内存。因此 C 有一些函数,调用者也可以指定最大值,例如strncpy.

在 C++ 中,如果需要,让被调用函数处理内存分配是很常见的。例如vector::push_back。但是,C++ 仍然有调用者负责的函数,例如std::memcpy。

因此没有规定其中之一的规则。但是,如果可能的话,让被调用函数处理内存分配似乎是最好的做法。

仍然存在调用者可以通过参与分配获得更好性能的情况。示例:您调用传递(引用)向量的函数,被调用的函数会将数据放入向量中。如果调用者知道将添加(push_backed)很多新元素并且调用者知道大概的数字(例如 8000 到 10000),则调用者可以通过在调用之前在向量中保留 10000 个条目来提高性能。所以这就像一个共同的努力。但是被调用的函数仍然可以安全地处理需要超过 10000 个条目的情况。

【讨论】:

【参考方案2】:

我见过的要求调用者为工作数组分配内存的“旧”代码是在动态内存分配成为计算语言的标准部分之前编写的(或编写它们的重要组件)。 (例如,参见 Fortran 77。)他们之所以没有这样做,是因为他们认为这是一种很好的做法,因为计算机科学还没有发展到足够的程度。除非您出于遗留原因链接到这样的库,否则动态分配是更好的选择。

【讨论】:

【参考方案3】:

通常,如果您的函数需要一个长度未知且最大大小不小的数组,那么正确的处理方法是使用newmalloc 并在堆上分配内存.

举例来说,您需要解析一个文件并将其内容读入一个数组,而您不知道该文件的使用时间有多长,那么使用vector<> 将是正确的方法。然后,当您调用 push_back() 时,您添加的元素会进入堆中的某个位置。

【讨论】:

【参考方案4】:

“堆或传递工作内存”中,您提出了一种错误的二分法——到目前为止,最常见的做法是被调用的函数使用堆栈进行“工作” “ 记忆。使用堆栈比动态分配更快,并确保在执行离开变量的包含范围时解除分配,即使由于异常也是如此。

如果被调用函数正在准备一个值以返回给调用者......这不仅仅是“工作”内存,我认为这不是你要问的,但 FWIW 在这种情况下被调用者可能希望将内存与堆栈分离,以允许数据的生命周期比它自己的生命周期更长。这通常使用动态分配来完成,或者在返回标准库容器时隐式地完成,或者使用new 显式地完成(希望共享指针)。

【讨论】:

以上是关于在堆上分配内存还是传递工作内存? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

java创建对象时分配内存方式,是堆上分配还是栈上分配?

使用 malloc 在堆上分配内存的幕后花絮

为啥要在堆上而不是栈上分配内存? [复制]

我应该啥时候在堆上分配? (C++)

内存分配

go的值类型和引用类型2——内存分配规则