Windows窗体调用导致堆栈溢出?

时间:2013-11-01 21:52:27

标签: c# stack-overflow invoke

我正在为一个游戏制作一个记忆读取器,我在后台运行一个几乎无限的线程来检查玩家位置,然后使用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分钟,我无法获得太多关于它的信息。

2 个答案:

答案 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);
    }
}