【发布时间】:2010-12-22 19:52:06
【问题描述】:
我有一个用 Delphi W32 编写的应用程序,它处于测试阶段。
在测试 PC 上,使用几个小时后,它会随意弹出“堆栈溢出”消息。
如何捕获错误并找到原因?
我可以增加堆栈大小吗?
【问题讨论】:
-
提高堆栈大小几乎肯定只会减少不可避免的问题,也许您应该减少它以便更早地发现问题?
标签: delphi stack-overflow
我有一个用 Delphi W32 编写的应用程序,它处于测试阶段。
在测试 PC 上,使用几个小时后,它会随意弹出“堆栈溢出”消息。
如何捕获错误并找到原因?
我可以增加堆栈大小吗?
【问题讨论】:
标签: delphi stack-overflow
您应该减少链接器选项中的堆栈大小。然后在调试器下运行它,希望问题会出现,而无需等待两个小时。
【讨论】:
获取madExcept,它会准确告诉您故障发生时发生的情况。你会看到完整的堆栈,尤其是在它逃跑的地方。
【讨论】:
我几乎要说:在调试器中运行它;^)
我以前做的是在每个方法中添加一个进入和离开日志功能。通过适当的缩进,我可以在日志中追踪调用路径。
当发生堆栈溢出时,它会在日志中真正可见,因为缩进级别应该是通过屋顶
void someMethod()
{
logMethodEnter("someMethod");
... do stuff...
log("something")
... do stuff...
logMethodLeave("someMethod");
}
记录器会跟踪当前的日志深度并记录如下内容:
>someMethod
something
<someMethod
【讨论】:
您是否在测试机器上安装了 IDE?如果是这样,请尝试从 IDE 中重现该问题。当发生堆栈溢出时,查看调用堆栈(View->Debug Windows->Call Stack)。它可能会多次调用相同的函数,如下所示:
FunctionA
FunctionB
FunctionA
FunctionB
FunctionA
FunctionB
...
如果你看到了,那么你就知道这些函数在没有结束的情况下互相调用。
如果您没有在测试机器上安装 IDE,那么您仍然可以通过远程调试来执行此操作。如果您提供有关您的方案的更多信息,我们可能会提供更多帮助。
具体来说,了解一下可能会有所帮助:
【讨论】:
您可以使用项目链接器选项或 $M 编译器指令增加堆栈大小,但我认为除非堆栈非常小,否则它不会解决问题。
如果您在调试器中运行应用程序,它最终会在异常处中断。
【讨论】:
如果您使用线程(不是主 ex:sock 连接)和主线程,那么它们共享同一个堆栈。以这种方式解决:只需为每个连接创建一个具有自己堆栈的线程。
问题 > 你做的每一个调用都会为帧调用堆栈(共享一个这么大的问题) 例如,您调用 proc aa(a,b:integer) 例如始终调用相同或不同的函数;
您有一个套接字线程正在运行,并且 onconnect 您调用 proc a;并保持做某事需要 5 秒。
如果有人在 on connect close 连接(释放堆栈)之前连接。 您有 2 个连接的客户端(2 个不同的堆栈帧,每个不同的数据)
堆栈
推 a,b (整数);值 5,10 - 来自 1 个连接
推 a,b (整数);值 7,3 - 来自 2 conn
如果 onconnect 调用函数 a(5,10) 并保持做某事大约 5 秒。 并且有人再次连接到服务器套接字,它再次调用连接。
堆栈旧第一个调用帧但还没有退出 proc。所以没有从 (5,10) 弹出 a,b
如果您再次调用 proc 会比这更复杂,那么它将覆盖 2 帧上的数据(2 个连接的本地 proc 变量),因此当 2 个连接从堆栈获取数据时,肯定已经被其他信息覆盖。所以它会做不正确的行为。
当第一个连接断开时会弹出 a,b 但 7,3(来自第二个连接)而不是它保存的 5,10。因此它不会立即堆栈溢出,而是稍后随着程序运行和堆栈释放错误,您最终会得到一个$FFFFFFFF $SP 堆栈。所以当你调用一个函数时它会尝试$FFFFFFAA,所以它比你的堆栈大:$M 65536,而不是$FFFFFFAA的4 GB。
【讨论】: