0

以下程序顯示一個計數器,顯示垃圾收集的負載。C#解釋和GC(垃圾收集)計數器

我希望能夠在一段時間內看到負載,例如以MB爲單位,例如每1/60秒幀。

using System; 
using Microsoft.Xna.Framework; 
using Microsoft.Xna.Framework.Graphics; 

namespace proj 
{ 
    public class game : Microsoft.Xna.Framework.Game 
    { 
     private GraphicsDeviceManager graphics; 
     private SpriteBatch sprite_batch; 
     private SpriteFont font; 

     public game() 
     { 
      graphics = new GraphicsDeviceManager(this); 
     } 

     protected override void Initialize() 
     { 
      Content.RootDirectory = "Content"; 
      sprite_batch = new SpriteBatch(GraphicsDevice); 
      font = Content.Load<SpriteFont>("font"); 
      base.Initialize(); 
     } 

     protected override void Update(
      GameTime game_time) 
     { 
      //base.Update(game_time); 
     } 

     protected override void Draw(
      GameTime gameTime) 
     { 
      GraphicsDevice.Clear(
       Color.DarkBlue); 
      sprite_batch.Begin(); 
      sprite_batch.DrawString(
       font, 
       ((float)GC.GetTotalMemory(true)/(1024 * 1024)).ToString(), 
       //GC.GetTotalMemory(true).ToString(), 
       new Vector2(20, 20), 
       Color.White); 
      sprite_batch.End(); 
      //base.Draw(gameTime); 
     } 
    } 
} 

但是我看到剛剛超過0.4MB,這似乎高了這個節目,我希望在幕後創建每幀一些新的對象,但除此之外,我只能看到一個Vector2和幾個數字以及在創建((float)GC.GetTotalMemory(true)/(1024 * 1024)).ToString()期間的字符串值。

在一個較大的程序中,在繪製和更新過程中很少發生,因爲我已經包裝了在註釋中會發生什麼,但是存在很多代碼,其中一些代碼在程序開始時運行一次,程序顯示每幀90MB的恆定負載。

更重要的是,我已經嘗試添加:

pos n2; 
for (UInt32 n = 0; n < 100000; n++) 
{ 
    n2 = new pos(n, 0); 
    func(n2); 
} 

public class pos 
{ 
    public pos(
     float x, 
     float y) 
    { 
     this.x = x; 
     this.y = y; 
    } 

    public float 
     x, y; 
} 

private void func(
    pos p) 
{ 
} 

要繪製,而GC價值變化很小。

我解釋錯了嗎?如果是這樣,那麼我如何顯示我所需要的?

看起來好像GC對我造成了性能問題,以每秒一次的執行暫停的形式出現。它們在PC上幾乎不可見,但在XBOX上非常明顯。我正在這樣做來分析是否屬於這種情況。

我所能例如優化(從視圖代碼的性能點時運行)這樣的代碼:

loop() 
{ 
    func(new pos(..., ...)); 
} 

到像代碼:

pos p = new pos(0, 0); 
loop() 
{ 
    p.x = ...; 
    p.y = ...; 
    func(p); 
} 

雖然這是可疑地相關,它可能會問。我對GC的立場是,如果沒有它,我不會選擇使用OO編程語言。我認爲創建好的代碼至關重要。


澄清。我一直在尋找垃圾回收器的負載。 GC似乎以字節的形式返回此信息,但返回的值似乎與整個程序的總內存使用率更加一致。


我看到沒有人真的回答了這個問題,有一個關閉請求,這個問題已經結束了巨大的,我保持具有明顯的細節進行更新。在這裏,人們完全錯過了這一點似乎很容易。我不明白爲什麼我的應用程序GC載入計數器沒有顯示明顯不正確的結果,例如當每個幀出現不正確的情況時,都有90MB的空間。

現在已經超出了對我的實際用處,因爲它已經這麼長時間了。

+0

帶有loop()的第二個片段不會導致任何垃圾,但請注意,您有公共可變域。 –

+0

爲什麼要讓'pos'成爲一個類,爲什麼不直接使用'Vector2'呢? 'Vector2'是一個結構,所以它自己不會觸發堆分配。 –

+0

因爲在上面的問題中使用pos來創建垃圾來演示GC值如何不顯示我正在查找的值,然後作爲佔位符來顯示其他代碼如何優化。 – alan2here

回答

0

首先,如果你想優化內存,你應該使用內存分析器。它會告訴你所有你需要的細節(哪裏是瓶頸?我的代碼是導致它還是庫?)。像這樣建立助手是單調乏味且容易出錯的。另外,在目前的狀態不會告訴你很多,是嗎?其次,Vector2是一個值類型,所以new Vector2(20, 20)不應該導致任何垃圾(變量不關閉,沒有裝箱,沒有迭代器塊等)。如果您繪製多個字符串,請使用採用StringBuilder的DrawString。

private StringBuilder text = new StringBuilder(); 

    protected override void Update(GameTime game_time) 
    { 
     text.Remove(0, text.Length); 
     text.Append((float)GC.GetTotalMemory(true)/(1024 * 1024))); 
     //base.Update(game_time); 
    } 

如果是的話我怎麼顯示我的需要?

不確定如果我的問題是正確的,但要顯示一段時間內的內存使用情況,請使用定製工具。獲取一個分析器。

編輯:

更重要的是,我已經嘗試添加:

pos n2; 
for (UInt32 n = 0; n < 100000; n++) 
{ 
    n2 = new pos(n, 0); 
    func(n2); 
} 

什麼是正?它是像Vector2那樣的值類型嗎? Vector2不應該導致垃圾(通常)。

看起來好像GC對我造成的性能問題,以每秒一次的執行暫停的形式出現。它們在PC上幾乎不可見,但在XBOX上非常明顯。我正在這樣做來分析是否屬於這種情況。

我知道你的痛苦。顯而易見的解決方案是避免分配。如果你無法避免它,你可以建立一個簡單的緩存機制(一個HashSet /對象字典)並相應地更新這些值。在用戶開始遊戲之前儘可能加載。

+0

我一直在尋找垃圾收集器的負載。不是整個程序的內存使用率。 GC似乎以字節的形式返回這些信息。 – alan2here

+0

Pos與Vector2類似,但它是一個類,可變的,通過引用等傳遞...... – alan2here

+0

這是一個好主意,我已經預先計算了很多已加載。 – alan2here

1

我剛剛加入,所以我不能發表評論,但似乎你想要什麼:

"I'm looking for the load on the garbage collector over time. Not the memory useage of the whole program. The GC seems to return this information in the form of bytes" 

已經存在。只需使用已安裝在系統上的標準.net性能計數器即可。開始 - >控制面板 - >管理工具 - >性能監視器啓動你的應用程序打開perf監視器,然後選擇你的應用程序,並在.NET CLR內存計數器添加你所需要的。有很大的計數器可以幫助您瞭解您是否真的有GC問題,給出內存統計數據,更重要的是可以告訴您每代有多少內存,它們多久收集一次分配數/秒等。

Hope這有助於。

+0

謝謝。不幸的是,性能監視器不夠經常更新並且是單獨的程序。我也有一個分析器,這也是一個單獨的程序,在功能的另一個方向,我無法理解許多分析器複雜的圖形。 – alan2here