C# 解释和 GC(垃圾回收)计数器

本文关键字:计数器 解释 GC | 更新日期: 2023-09-27 18:33:15

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

我希望能够在一段时间内查看负载,例如以 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,这对于这个程序来说似乎很高,我希望每一帧都在幕后创建一些新对象,但除此之外,我只能在创建((float)GC.GetTotalMemory(true) / (1024 * 1024)).ToString()期间看到 Vector2 和一些数字和字符串值。

在一个较大的程序中,在绘制和更新期间同样很少发生,因为我已经将要发生的事情包装在注释中,但是存在很多代码,其中一些在程序开始时运行一次,该程序显示每帧 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。

它现在已经超出了对我的实际用处,因为它已经有这么长时间了。

C# 解释和 GC(垃圾回收)计数器

我刚刚加入,所以我不能发表评论,但这似乎是你想要的:

"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问题,提供内存统计信息,更重要的是可以告诉您每一代中有多少内存,它们每秒被收集分配的频率等。

希望这有帮助。

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

其次,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上非常明显。我这样做是为了分析是否是这种情况。

我知道你的痛苦。显而易见的解决方案是避免分配。如果无法避免,可以构建一个简单的缓存机制(对象的哈希集/字典(并相应地更新值。在用户开始游戏之前尽可能多地加载。