问题描述
|
有没有一种方法可以在堆栈而不是堆上分配内存?我找不到关于这方面的好书,这里有人知道吗?
解决方法
使用
alloca()
(有时称为_alloca()
或_malloca()
),但是要非常小心-它会在您离开函数时释放其内存,而不是在超出范围时释放,因此如果您在循环内使用它会很快炸毁。
例如,如果您有类似
int foo( int nDataSize,int iterations )
{
for ( int i = 0; i < iterations ; ++i )
{
char *bytes = alloca( nDataSize );
// the memory above IS NOT FREED when we pass the brace below!
}
return 0;
} // alloca() memory only gets freed here
然后,每次循环时,alloca()都会分配一个额外的nDataSize字节。从函数返回之前,不会释放alloca()字节。因此,如果您的nDataSize
为1024,而iterations
为8,则在返回之前将分配8 KB。如果您有nDataSize
= 65536和iterations
= 32768,那么您将分配总共65536×32768 = 2,147,483,648字节,几乎可以肯定会炸毁堆栈并导致崩溃。
轶事:如果您在缓冲区的末尾进行写操作,则很容易遇到麻烦,特别是如果将缓冲区传递给另一个函数,并且该子函数对缓冲区的长度有错误的认识。我曾经修复过一个相当有趣的错误,在该错误中,我们使用ѭ0来创建临时存储以呈现TrueType字体字形,然后再将其发送到GPU内存。我们的字体库在计算字形大小时并未考虑瑞典语Å字符的变音符号,因此它告诉我们在渲染前分配n个字节来存储字形,然后实际渲染n + 128个字节。额外的128个字节写入了调用堆栈,覆盖了返回地址并引发了非常痛苦的不确定性崩溃!
, 由于这是用C ++标记的,因此通常只需在正确的范围内声明所需的对象即可。它们在堆栈上分配,并保证在范围出口处释放。这是RAII,是C ++相对于C的关键优势。不需要malloc
s或new
s,尤其是不需要alloca
s。
, 您可以声明一个本地char[1024]
或任意数量的字节(最多一个字节),然后获取本地地址作为指向堆栈上该内存块的指针。并不是完全动态的,但是如果需要,您可以使用自己的内存管理器包装此内存。
, 讨论有关动态内存分配的文章
我们可以通过以下方式在堆栈内存上动态分配可变长度的空间:
使用功能
_alloca。该函数从程序堆栈分配内存。它只需要分配字节数,然后将void *返回给
分配的空间就像malloc调用一样。分配的内存将是
在功能退出时自动释放。
因此,无需显式释放它。必须牢记
此处分配大小,因为可能会发生堆栈溢出异常。堆
溢出异常处理可用于此类调用。的情况下
堆栈溢出异常可以使用_resetstkoflw()
恢复它
背部。
因此,我们带有code14ѭ的新代码将是:
int NewFunctionA()
{
char* pszLineBuffer = (char*) _alloca(1024*sizeof(char));
…..
// Program logic
….
//no need to free szLineBuffer
return 1;
}
, 参见ѭ16。
, 当/如果C ++允许将(非静态))17ѭ值用于数组范围,则将更加容易。
目前,我所知道的最好方法是通过递归。有各种各样聪明的方法可以完成,但是我所知道的最简单的方法是让您的例程声明一个固定大小的数组,并对其进行填充和操作。完成后,如果需要更多空间来完成,它会自行调用。
, 您可以使用BDE C ++库,例如
const int BUFFER_SIZE = 1024;
char buffer[BUFFER_SIZE];
bdlma::BufferedSequentialAllocator allocator(buffer,BUFFER_SIZE);
bsl::vector<int> dataVector(&allocator);
dataVector.resize(50);
BDE提供了全面的分配器选项以及bsl :: vector之类的集合,这些集合可以使用多态分配器,而无需更改容器的类型。
您可能还会考虑:
https://github.com/facebook/folly/blob/master/folly/docs/small_vector.md
http://www.boost.org/doc/libs/1_55_0/doc/html/container/non_standard_containers.html#container.non_standard_containers.static_vector
http://llvm.org/docs/doxygen/html/classllvm_1_1SmallVector.html