2013-11-01 5 views
1

Я делаю считыватель памяти для игры, и у меня есть почти бесконечный поток, работающий в фоновом режиме, который проверяет позицию игроков, а затем отображает его на ярлыке с помощью Invoke(). Я отправлю только оскорбительную функцию. Это вызывает один и тот же поток каждые 10 мс.Windows Forms Invoke вызывает переполнение стека?

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

StackOverflowException предполагает стек вызовов слишком глубоко, вероятно, какой-то неограниченной рекурсией. Я подозреваю, что проблема не в коде, который вы показываете, а в том, как вы его называете. Не могли бы вы разместить стек вызовов в момент исключения? это поможет. Вы можете отредактировать свой вопрос. – Theraot

+0

Предполагаю, что вы снова и снова создаете экземпляры объекта. – DaveDev

+0

Код, который вы показали, сам по себе не вызовет SOE. Вам нужно будет предоставить достаточно, чтобы воспроизвести проблему. – Servy

ответ

0

Должно ли это иметь цикл while вместо того, чтобы называть себя? Да, конечно.

Sanly C# не будет генерировать хвостовые вызовы для этого кода, то есть он будет складывать вызовы UpdateThread до тех пор, пока стек вызовов не будет заполнен. Это вызывает StackOverflowException.

Таким образом, вы бы реализовать что-то вроде этого:

private void UpdateThread() 
{ 
    while (running) //I'm assuming running is a volatile variable 
    { 
     ReadPos(); 
     Thread.Sleep(100); 
    } 
} 

Примечание: Это хорошая идея, чтобы продолжить неустойчивыми, так как он будет установлен другой нитью (я полагаю).

Вы также можете рассмотреть возможность публикации выполнения в цикл потока или аналогичный механизм планирования вместо того, чтобы иметь выделенный поток, в этом отношении выполните свое тестирование, чтобы увидеть, что лучше всего работает.


Другим важным моментом является то, чтобы сохранить свой объект делегата живым, это уменьшит давление на сборщик мусора (так как вы в настоящее время создает слишком много короткоживущих объектов), но это не причина StackOverflowException.

+0

Хорошо, спасибо. Я предположил, что было бы хорошо продолжать повторный вызов метода, потому что я видел его в куче учебников. – Jordan

+0

@ Jordan - это те учебники для C#? Позор им! Это было бы хорошо на языке, который генерирует правильные хвостовые вызовы (такие как F #), но не в C#. – Theraot

+0

Да, они были для C#, поэтому я и сделал это. – Jordan

0

Да, вы должны использовать петлю вместо этого.

Вы используете рекурсию для создания цикла, и поскольку цикл не имеет разумного предела, он заполняет стек кадрами вызовов.

Просто цикл внутри метода:

private void UpdateThread() 
{ 
    while (running) { 
     ReadPos(); 
     Thread.Sleep(100); 
    } 
} 
Смежные вопросы