gpt4 book ai didi

delphi - delphi中的堆栈溢出错误

转载 作者:行者123 更新时间:2023-12-03 15:04:05 24 4
gpt4 key购买 nike

我有一个调用多个函数的过程:

procedure TForm1.Button1Click(Sender: TObject);
var
rawData: TRawData;
rawInts: TRawInts;
processedData: TProcessedData;
begin
rawData := getRawData();
rawInts := getRawInts(rawData);
processedData := getProcessedData(rawInts);
end;

数据类型定义如下:

TRawData = array[0..131069] of Byte;
TRawInts = array[0..65534] of LongInt;
TProcessedData = array[0..65534] of Double;

运行程序只需:

rawData := getRawData();
rawInts := getRawInts(rawData);

工作完全正常。但是,当我尝试运行时:

getProcessedData(rawInts)

我收到一个 stackoverflow 错误。我不明白这是为什么。 getProcessedData的函数代码非常简单:

function getProcessedData(rawInts : TRawInts) : TProcessedData;
var
i: Integer;
tempData: TProcessedData;
scaleFactor: Double;
begin
scaleFactor := 0.01;

for i := 0 to 65534 do
tempData[i] := rawInts[i] * scaleFactor;

Result := tempData;
end;

为什么这会导致错误?

最佳答案

线程的默认最大堆栈大小为 1 MB。 Button1Click 的三个局部变量总计 131,070 + 65,535 * 4 + 65,535 * 8 = 917,490 字节。当您调用getProcessedData 时,您按值传递参数,这意味着函数会在堆栈上创建参数的本地副本。这会增加 SizeOf(TRawInts) = 262,140 字节,使堆栈至少达到 1,179,630 字节,即大约 1.1 MB。这是你的堆栈溢出。

您可以通过引用传递 TRawInts 数组来减少堆栈使用。那么该函数将不会创建自己的副本。 Zdravko's answer建议使用var,但由于函数不需要修改传入的数组,所以应该使用const

function getProcessedData(const rawInts: TRawInts): TProcessedData;

天真地,我们可能期望 getProcessedData 中的 tempDataResult 变量占用额外的堆栈空间,但实际上,它们可能不会” t。首先,大的返回类型通常会导致编译器更改函数签名,因此它的行为更像是使用 var 参数而不是返回值声明函数:

procedure getProcessedData(rawInts: TRawInts; var Result: TProcessedData);

然后调用会相应地转换:

getProcessedData(rawInts, processedData);

因此,Result 不会占用更多堆栈空间,因为它实际上只是调用者框架中变量的别名。

此外,有时编译器会识别出函数末尾的赋值,例如 Result := tempData,意味着 tempData 实际上不需要任何空间它自己的。相反,编译器可能会将您的函数视为一直直接写入 Result 中:

begin
scaleFactor := 0.01;

for i := 0 to 65534 do
Result[i] := rawInts[i] * scaleFactor;
end;

但是,最好不要指望编译器进行此类节省内存的更改。相反,最好一开始就不要过分依赖堆栈。为此,您可以使用动态数组。这些会将大量内存移出堆栈并移入,这是用于动态分配的内存部分。首先更改数组类型的定义:

type
TRawData = array of Byte;
TRawInts = array of Integer;
TProcessedData = array of Double;

然后,在返回这些类型的函数中,使用 SetLength 分配每个数组的长度。例如,我们已经见过的函数可能是这样的:

function getProcessedData(const rawInts: TRawInts): TProcessedData;
var
i: Integer;
scaleFactor: Double;
begin
Assert(Length(rawInts) = 65535);
SetLength(Result, Length(rawInts));

scaleFactor := 0.01;

for i := 0 to High(rawInts) do
Result[i] := rawInts[i] * scaleFactor;
end;

关于delphi - delphi中的堆栈溢出错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22697837/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com