我正在为一个游戏制作一个记忆读取器,我在后台运行一个几乎无限的线程来检查玩家位置,然后使用Invoke()将其显示在标签上。我只会发布有问题的功能。这会在每10毫秒在同一个线程上调用。
Invoke((MethodInvoker)delegate
{
lblCoords.Text = "Player Coordinates: < " + (int)x + ", " + (int)y + ", " + (int)z + " >";
});
代码运行约20分钟后,它将崩溃并抛出与此函数相关的StackOverflowException。为什么会这样,我怎么能阻止它呢?显然我可以停止使用标签来显示它,但知道它为什么会发生以供将来参考会更有用。
所以这是线程方法,有人提到它是多个对象一次创建,我会假设它是因为它是一个无限循环调用UpdateThread()...这应该有一个while循环而不是自称?
private void UpdateThread()
{
if (!running) return;
ReadPos();
Thread.Sleep(100);
UpdateThread();
}
private void ReadPos()
{
int pointerAddress = Memory.HexToDec(MemoryOffsets.PlayerPosAddress);
byte[] xVal = memory.PointerRead((IntPtr)pointerAddress, 4, MemoryOffsets.PlayerX);
byte[] yVal = memory.PointerRead((IntPtr)pointerAddress, 4, MemoryOffsets.PlayerY);
byte[] zVal = memory.PointerRead((IntPtr)pointerAddress, 4, MemoryOffsets.PlayerZ);
float x = BitConverter.ToSingle(xVal, 0);
float y = BitConverter.ToSingle(yVal, 0);
float z = BitConverter.ToSingle(zVal, 0);
Invoke((MethodInvoker)delegate
{
lblCoords.Text = "Player Coordinates: < " + (int)x + ", " + (int)y + ", " + (int)z + " >";
});
}
程序显示的错误指向了Invoke方法,这就是为什么我认为它只是导致它的原因。由于异常发生大约需要20分钟,我无法获得太多关于它的信息。
答案 0 :(得分:0)
这应该有一个while循环而不是自己调用吗?是的,无论如何。
Sanly C#不会为此代码生成尾调用,这意味着它将堆叠UpdateThread
的调用,直到调用堆栈已满。这导致StackOverflowException
。
所以,你会实现这样的东西:
private void UpdateThread()
{
while (running) //I'm assuming running is a volatile variable
{
ReadPos();
Thread.Sleep(100);
}
}
注意:最好让运行volatile,因为它将由另一个线程设置(我假设)。
您还可以考虑将执行发布到线程循环或类似的调度机制,而不是拥有专用线程,就此而言,进行测试以查看最佳效果。
要考虑的另一件事是让你的委托对象保持活跃状态,它将减少对垃圾收集器的压力(因为你当前正在创建太多的短期对象),但它不是StackOverflowException
的原因。
答案 1 :(得分:0)
是的,你应该使用一个循环。
您正在使用递归来进行循环,并且由于循环没有合理的限制,它将使用调用框填充堆栈。
只需在方法内循环:
private void UpdateThread()
{
while (running) {
ReadPos();
Thread.Sleep(100);
}
}