【问题标题】:C# Interpretation and the GC (garbage collection) counterC# 解释和 GC(垃圾回收)计数器
【发布时间】:2012-05-13 23:29:10
【问题描述】:

以下程序显示一个计数器,显示垃圾收集的负载。

我希望能够查看一段时间内的负载,例如以 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() 正在创建中。

在一个较大的程序中,在绘制和更新过程中几乎没有发生类似的事情,因为我已经包装了 cmets 中会发生的事情,但是存在很多代码,其中一些在程序开始时运行一次,程序显示恒定负载每帧 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。

它现在对我来说已经超出了实际用途,因为它已经很长时间了。

【问题讨论】:

  • 第二个带有 loop() 的 sn-p 不会造成任何垃圾,但请注意您有公共可变字段。
  • 为什么要将pos 设为一个类,为什么不直接使用Vector2Vector2 是一个结构体,所以它本身不会触发堆分配。
  • 因为在上述问题中使用 pos 来创建垃圾以演示 GC 值如何不显示我正在寻找的值,然后 purly 作为占位符来显示如何优化其他代码.

标签: c# debugging optimization garbage-collection performancecounter


【解决方案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 性能计数器。开始->控制面板->管理工具->性能监视器启动您的应用程序打开性能监视器,然后选择您的应用程序并在 .NET CLR 内存计数器下添加您需要的内容。有很好的计数器可以帮助您查看您是否真的有 GC 问题,提供内存统计信息,更重要的是可以告诉您每一代有多少内存,它们被收集分配的频率/秒等。

希望这会有所帮助。

【讨论】:

  • 谢谢。不幸的是,性能监视器更新的频率不够高,并且是一个单独的程序。我还有一个分析器,这也是一个单独的程序,在功能的另一个方向上,我无法理解许多分析器复杂的图表。
【解决方案2】:

首先,如果你想优化内存,你应该使用内存分析器。它会向您显示您需要的所有细节(瓶颈在哪里?我的代码是导致它还是库?)。像这样构建助手既乏味又容易出错。另外,在目前的状态下不会告诉你太多,不是吗?

其次,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/Dictionary)并相应地更新值。尽可能在用户开始游戏之前加载。

【讨论】:

  • 我正在寻找垃圾收集器上的负载随着时间的推移。不是整个程序的内存使用量。 GC 似乎以字节的形式返回此信息。
  • “我正在寻找垃圾收集器上的负载。而不是整个程序的内存使用情况”分析器会告诉你哪个代码导致最多的分配。你应该先优化它。
猜你喜欢
  • 2014-08-26
  • 1970-01-01
  • 1970-01-01
  • 2023-03-30
  • 2011-11-29
  • 2021-12-20
  • 1970-01-01
  • 2013-06-02
  • 1970-01-01
相关资源
最近更新 更多