有没有办法在堆栈上分配内存,而不是在堆上?我找不到一本好的书来解决这个问题,这里有人有想法吗?
使用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千字节。如果nDataSize
=65536且iterations
=32768,则总共分配65536×32768=2,147,483,648个字节,几乎肯定会使堆栈溢出并导致崩溃。
趣闻轶事: 如果您超出缓冲区的末尾,尤其是如果您将缓冲区传递给另一个函数并且该子函数错误地估计了缓冲区的长度,那么您很容易遇到麻烦。 我曾经修复过一个非常有趣的错误,我们使用alloca()
为渲染TrueType字体字形创建临时存储,然后将其发送到GPU内存。 我们的字体库在计算字形大小时没有考虑到瑞典语中Å字符的变音符号,因此它告诉我们要分配n字节来存储字形,然后实际上渲染了n+128字节。额外的128个字节写入调用堆栈,覆盖返回地址并导致非常痛苦的非确定性崩溃!
由于这是标记为C++,通常只需在正确的作用域中声明所需的对象。它们分配在堆栈上,并保证在作用域退出时被释放。这是C++相对于C的关键优势之一,称为RAII。不需要malloc
或new
,尤其是不需要alloca
。
您可以声明一个本地的char[1024]
或任何您想要的字节数(在一定程度上),然后获取该本地地址,作为指向堆栈上该内存块的指针。虽然不是完全动态的,但如果需要,您可以将此内存与自己的内存管理器包装起来。
We can allocate variable length space dynamically on stack memory by using function _alloca. This function allocates memory from the program stack. It simply takes number of bytes to be allocated and return void* to the allocated space just as malloc call. This allocated memory will be freed automatically on function exit.
So it need not to be freed explicitly. One has to keep in mind about allocation size here, as stack overflow exception may occur. Stack overflow exception handling can be used for such calls. In case of stack overflow exception one can use
_resetstkoflw()
to restore it back.So our new code with
_alloca
would be :
int NewFunctionA() { char* pszLineBuffer = (char*) _alloca(1024*sizeof(char)); ….. // Program logic …. //no need to free szLineBuffer return 1; }
如果 C++ 允许使用(非静态)const
值作为数组边界,那将更加容易。
目前,我知道的最佳方法是通过递归实现。有各种巧妙的技巧可供选择,但我知道的最简单的方法是让您的程序声明一个固定大小的数组,并填充和操作它所拥有的内容。当完成时,如果需要更多空间来完成任务,则调用自身。
const int BUFFER_SIZE = 1024;
char buffer[BUFFER_SIZE];
bdlma::BufferedSequentialAllocator allocator(buffer, BUFFER_SIZE);
bsl::vector<int> dataVector(&allocator);
dataVector.resize(50);
vector
,但如果该函数在紧密循环中被调用,那么如果内存可以快速分配和释放而不必担心碎片化,那就太棒了。 - André Caron