0

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

我希望能够在一段时间内(例如每 1/60 秒帧)查看负载,例如以 MB 为单位。

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。

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

4

2 回答 2

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

希望这可以帮助。

于 2012-05-06T01:53:42.377 回答
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);
}

什么是pos?它是像 Vector2 这样的值类型吗?Vector2 不应导致垃圾(通常)。

似乎 GC 对我造成了性能问题,以大约每秒一次的执行暂停形式出现。它们在 PC 上几乎看不到,但在 XBOX 上却非常明显。我这样做是为了分析是否是这种情况。

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

于 2012-05-06T00:35:51.657 回答