2012-04-03 32 views
0

在此時,應用程序消耗大約150MB的內存。看看這個:查詢正在使用的內存崩潰應用程序?

異常訊息話題:

類型 'System.OutOfMemoryException的' 引發的異常。

堆棧跟蹤: 在System.Diagnostics.NtProcessInfoHelper.GetProcessInfos() 在System.Diagnostics.ProcessManager.GetProcessInfos(字符串機器名) 在System.Diagnostics.Process.EnsureState(州狀態) 在System.Diagnostics程序。在Streamsink.frmMain.CalculateStatistics()中的C:\ Projects \ Streamsink \ \ VideoPhill \ PlayerRAC \ StreamSink \ StreamSink \ StreamSink \ frmMain.cs:第803行 位於C:\ Projects \ VideoPhill \ PlayerRAC \ StreamSink \ StreamSink \ StreamSink \ frm中的StreamSink.frmMain._timerUI_T​​ick(Object sender,EventArgs e) Main.cs:行736 在System.Windows.Forms.Timer.OnTick(EventArgs五) 在System.Windows.Forms.Timer.TimerNativeWindow.WndProc(消息&米)

那麼,什麼是錯的這裏?

EDIT(詳細信息):

這一次失敗:

private long MemoryUsed 
    { 
     get 
     { 
      return Process.GetCurrentProcess().WorkingSet64/1024/1024; 
     } 
    } 

,距離稱爲:

private void CalculateStatistics() 
    { 
     if (InvokeRequired) 
     { 
      this.BeginInvoke(new MethodInvoker(CalculateStatistics)); 
     } 
     else 
     { 
      barStaticItem1.Caption = "Mem: " + MemoryUsed.ToString() + " MB"; 
     } 
    } 

是從計時器事件調用,和定時器的類型是: System.Windows.Forms.Timer

*錯誤不能自行復制。 *

+0

(因爲我現在正在刪除我的答案,將此評論移至提問處):嗯,看起來有點奇怪。我仍然懷疑計時器可能與它有關。如果你改變它會發生什麼,所以這個調用不是由定時器觸發的? – 2012-04-09 22:17:08

+0

@BrianRasmussen沒有嘗試過,因爲每兩個星期發生一次,只有在生產中。沒有機會故意挑釁它... – 2012-04-10 06:41:19

+0

@DanielMošmondor:請您發佈完整的repro代碼(àla http://www.yoda.arachsys.com/csharp/complete.html)? – 2012-04-10 13:34:34

回答

1

我會在這裏出去看看,注意到有些東西是可疑的。首先,你爲什麼要寫這樣的代碼?它實際上是共同爲應用程序用盡內存和這是爲什麼你想顯示內存使用情況在您的用戶界面?其次,你如何確定應用程序實際上只使用了150 MB,如果這種情況發生在生產環境中,而不是在你的開發機器上?

我會認爲這個例外是真實的,假設是不好的。這個過程實際上用完了內存。這發生在旨在警告用戶內存條件不足的代碼中,這非常具有諷刺意味。但當然不是不可能的,當機器上運行大量進程時,提供信息的本地OS功能需要相當大的緩衝區。您應該使用Environment.WorkingSet屬性。

另外值得注意的是,從WorkingSet中獲取150 MB並仍然獲得OOM是很有可能的。這是錯誤內存統計信息。 WorkingSet描述您使用多少RAM。但是當您用完虛擬內存時會觸發OOM。兩個非常不同的措施。當虛擬內存頁面被換出到頁面文件時WorkingSet較低。當很多進程正在運行時,這很可能發生,爭奪RAM。

沒有方便的屬性可用來衡量VM大小。主要是因爲它在很大程度上是無用的,所以內存映射中的空洞大小是重要的。當沒有足夠大的孔來適應分配時,你會得到OOM。如果你想顯示一個有用的統計信息,那麼GC.GetTotalMemory()有些用處。只是在一定程度上,它沒有考慮到使用中的非託管內存。通過在您的要求中指定一個64位操作系統來解決所有問題。

+0

謝謝,我想你的文章是對那裏發生的事情的最好解釋,因爲你猜對了,其他應用程序正在從無辜的只有150MB的應用程序中竊取內存。我不同意一些聲明,但是我知道的只是你現在遇到的情況。 – 2012-04-15 18:24:59

0

如果BeginInvoke在這裏有某些事情需要做(因爲我們不知道什麼時候InvokeRequired是真的),您的代碼真的不會顯示。

所以,很顯然這個代碼可能會失敗,因爲所有其他的代碼看起來不錯:

Process.GetCurrentProcess().WorkingSet64/1024/1024; 

我建議你做一個小的應用程序,其壓力測試Process.GetCurrentProcess()工作集。但是,如果是真的,我懷疑它會有幫助(除非你的生產機器有一些硬件問題)。

我看到你你正在使用barStaticItem1 - 應該是一個控件,不是嗎?那麼,如果你正在啓動不同的線程,並且這個控件不是線程安全的或者不應該被其他線程使用(與創建這個控件的線程不同),這可能是你的問題的一個來源:1.很少發生; 2.當你想要的時候你不能讓它發生。

+0

我們知道InvokeRequired不是真的,因爲我們有調用堆棧上面,如果它是真的,它不會看起來像這樣... – 2012-04-11 02:58:38

+0

然後從你的例子中刪除這部分代碼 – Dima 2012-04-11 08:21:21

+0

不會,因爲粘貼代碼和整個問題陷入越來越深入毫無意義:) – 2012-04-11 09:47:01

1

您可能會看到OutOfMemoryException從該調用堆棧中拋出,原因很簡單,該代碼反覆運行(來自定時器)。實際上消耗所有內存的代碼可能位於其他地方 - 計時器運行代碼剛好碰巧運氣不好,以致於在沒有太多剩餘時間的情況下嘗試獲取更多內存。

如果你不能想出應用程序應該使用這麼多內存的任何原因,那麼很可能你會在某處發生內存泄漏。您可能需要考慮抓取像ANTS Memory Profiler這樣的內存分析器來檢查是否屬於這種情況,如果存在,請檢查其位置。

0

我認爲失敗的原因是該代碼是在後臺線程重複執行,並且有沒有在遞歸調用this.BeginInvoke(new MethodInvoker(CalculateStatistics));

更改爲下面的代碼將有助於解決該問題的任何退出的條件。

private void CalculateStatistics() 
    { 

     Action showMemoryUsage =() => 
            { 
             barStaticItem1.Caption = "Mem: " + MemoryUsed.ToString() + " MB"; 
            }; 
     if (InvokeRequired) 
     { 
      this.BeginInvoke(new MethodInvoker(showMemoryUsage)); 
     } 
     else 
     { 
      showMemoryUsage(); 
     } 
    } 
相關問題