当内存不足时,如何防止变长数组崩溃?
在支持可变长度数组之前,我会像这样动态分配它们:
int foo(size_t n)
{
int *arr = malloc(n * sizeof int);
if (!arr) return ENOMEM; /* not enough memory */
.
. else do stuff with arr[]
.
free(arr);
return 0;
}
使用可变长度数组,我现在可以让它看起来更干净:
int bar(size_t n)
{
int arr[n];
.
. do stuff with arr[]
.
return 0;
}
但是现在我没有“内存不足”检查。事实上,如果 n 太大,程序就会崩溃。
如果 n 太大,我该如何优雅地退出 bar(n) ?
Before variable-length arrays were supported, I would dynamically allocate them like this:
int foo(size_t n)
{
int *arr = malloc(n * sizeof int);
if (!arr) return ENOMEM; /* not enough memory */
.
. else do stuff with arr[]
.
free(arr);
return 0;
}
With variable-length arrays I can now make it look cleaner:
int bar(size_t n)
{
int arr[n];
.
. do stuff with arr[]
.
return 0;
}
But now I have no "out of memory" checking. In fact, the program crashes if n is too big.
How can I gracefully bail from bar(n) if n is too big?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这种情况与任何其他局部变量完全相同 - 像这样的声明:
具有完全相同的问题。 “解决方案”与以往一样 - 不要递归得太深,并且不要分配具有自动存储持续时间的非常大的数据结构(在这些情况下继续使用
malloc()
)。 “非常大”的值在很大程度上取决于您的环境。换句话说,不要声明
int array[n];
除非您知道n
限制为一个合理的值,这样您会很乐意声明一个该最大大小的数组作为普通的非可变修改类型数组。(是的,这意味着可变修改类型数组并不像它们第一次出现时那么有用,因为与仅以所需的最大大小声明数组相比,您获得的收益很少)。
The situation is exactly unchanged from any other local variables - a declaration like this:
has exactly the same problem. The "solution" is the same as it always has been - don't recurse too deeply, and don't allocate very large data structures with automatic storage duration (continue to use
malloc()
for these cases). The value of "very large" depends strongly upon your environment.In other words, don't declare
int array[n];
unless you know thatn
is bounded to a reasonable value, such that you would have been happy to declare an array of that maximum size as an ordinary, non-variably-modified type array.(Yes, this means that variably-modified type arrays are not as useful as they first appear, since you gain very little over just declaring the array at the maximum needed size).
您可以通过不使用它们来防止它们崩溃。 :)
严肃地说,除非对大小有严格的限制,否则几乎没有安全的方法可以使用可变长度数组来使您的生活更轻松。另一方面,您可以有条件地使用它们,方式如下:
虽然这看起来像是无用的痛苦,但它可以带来巨大的性能差异,特别是在线程应用程序中,其中许多调用
malloc
和free
可能会导致锁争用。 (这个技巧的一个显着的副作用是,您可以通过简单地将[n < 1000 ? n : 1]
替换为1000
来支持没有 VLA 的旧编译器,例如用 VLA 可能有用的另一个模糊情况是在递归算法中,您知道所有递归级别所需的数组条目总数以
n
为界,其中n
> 足够小,您确信它不会溢出堆栈,但可能有最多n
级递归,并且单个级别最多使用n
个元素。在 C99 之前,处理这种情况而不占用n^2
堆栈空间的唯一方法是使用malloc
。使用VLA,您可以完全在堆栈上解决问题。请记住,VLA 真正有益的情况非常罕见。通常,VLA 只是一种欺骗自己的方法,让您相信内存管理很容易,直到您被所创建的(微不足道的)漏洞所困扰。 :-)
编辑:为了更好地解决OP的原始问题:
You can prevent them from crashing by not using them. :)
In all seriousness, there is almost no safe way to use variable-length arrays to make your life easier unless you have strong bounds on the size. On the other hand, you can use them conditionally, in ways like this:
While this looks like useless pain, it can make a huge performance difference, especially in threaded applications where many calls to
malloc
andfree
could result in lock contention. (A notable side benefit of this trick is that you can support old compilers without VLAs by simply replacing[n < 1000 ? n : 1]
with1000
, e.g. with a macro.)Another obscure case where VLAs may be useful is in recursive algorithms where you know the total number of array entries required across all levels of recursion is bounded by
n
, wheren
is small enough you're confident it won't overflow the stack, but where there could be up ton
levels of recursion and individual levels that use up ton
elements. Prior to C99, the only way to handle this case without takingn^2
stack space was to usemalloc
. With VLAs, you can solve the problem entirely on the stack.Keep in mind, these cases where VLAs are really beneficial are pretty damn rare. Normally VLA is just a way to deceive yourself that memory management is easy, until you get bit by the resulting (trivial-to-exploit) vulnerabilities you've created. :-)
Edit: To better address OP's original question:
实际上,在各处检查内存不足情况的成本非常高。处理海量数据的企业方法是通过在单个早期检查点定义大小硬性上限来限制数据大小,并在达到上限时快速而优雅地失败。
我刚才的建议既简单又愚蠢。但这是每个普通(非科学或特殊)产品总是做的事情。这也是客户通常所期望的。
In reality it is prohibitively expensive to check for out of memory conditions everywhere. The enterprisy way to deal with massive data is to limit data sizes by defining hard cap on size at single early checkpoint and fail fast and gracefully when the cap is hit.
What I just suggested is simple and stupid. But its what every ordinary (non-scientific or special) product always does. And its what normally is expected by customer.