C#Console CGI图形使用太多内存

时间:2017-10-25 16:01:06

标签: c# memory console drawing

我在c#中试验cgi。我做了一个应用程序,你可以在一个可以调整大小的矩形内移动一个正方形(带箭头)。我正在绘制一个矩形,以调整它的大小。我使用碰撞类限制移动经过边缘。

一切似乎都很好,但我担心它的内存使用情况。当我开始增加它的大小时,内存消耗会上升并触发GC。

有人可以帮我找到这个漏洞吗?我做错了什么会增加使用量?我是否以错误的方式使用缓冲区?

编辑::实际上,我发现导致内存使用的是这行代码。在注释掉这段代码之后,我的程序只使用了16MB而不是2GB。

   if (player.rectHeight >= tempWidth)
            {
                Program.bufferedGraphics = context.Allocate(Program.graphics, 
    new Rectangle(0, 0, Convert.ToInt32(player.rectWidth) + 100,
                Convert.ToInt32(player.rectHeight) + 100));
            }

感谢您的时间。

代码

class Program
{

    static Graphics graphics;
    static BufferedGraphics bufferedGraphics;
    static Player player;
    static Collision collision;
    static Utility utility;
    static SByte value = 0;
    static float tempWidth = 500;
    static void Main()
    {
        Program.player = new Player();
        Program.utility = new Utility();
        Program.collision = new Collision();
        Console.CursorVisible = false;
        Process process = Process.GetCurrentProcess();
        Program.graphics = Graphics.FromHdc(GetDC(process.MainWindowHandle));
        BufferedGraphicsContext context = BufferedGraphicsManager.Current;
        context.MaximumBuffer = new Size(Console.WindowWidth, Console.WindowHeight);
        Program.bufferedGraphics = context.Allocate(Program.graphics, new Rectangle(0, 0, Convert.ToInt32(player.rectWidth), 
            Convert.ToInt32(player.rectHeight)));


        while (true)
        {
            collision.worldEdges = new Collision.WorldEdges()
            {
                rightBorder = Convert.ToInt32(player.rectWidth),
                leftBorder = 0,
                topBorder = 0,
                bottomBorder = Convert.ToInt32(player.rectHeight),
            };
            if (player.rectHeight >= tempWidth)
            {
                Program.bufferedGraphics = context.Allocate(Program.graphics, new Rectangle(0, 0, Convert.ToInt32(player.rectWidth) + 100,
                Convert.ToInt32(player.rectHeight) + 100));
            }
            //Debug.Print(Convert.ToString(player.rectHeight));
            // Debug.Print(Convert.ToString(player.x));
            //Debug.Print(Convert.ToString(player.x- collision.worldEdges.rightBorder));
            if (player.y > collision.worldEdges.bottomBorder-19.7f) // if on the edge, clamp its movement
            {
                player.y = collision.worldEdges.bottomBorder-19.8f;


            }
            if (player.x > collision.worldEdges.rightBorder - 19.7)
            {
                player.x = collision.worldEdges.rightBorder - 19.8f;
            }
            else
            {
                Program.player.DoMove();
            }
            Program.player.ResizeScreen(out value); //check whether resize the rectangle

            if (value ==1) //g decrease size
            {
                bufferedGraphics.Graphics.FillRectangle(Brushes.Black, 0, 0, 
                    Convert.ToInt32(player.rectWidth), Convert.ToInt32(player.rectHeight));
                player.rectHeight -= 0.08f;
                player.rectWidth -=  0.08f;
                tempWidth = player.rectWidth;
            }
            if (value == -1) //h increase size
            {
                bufferedGraphics.Graphics.FillRectangle(Brushes.Black, 0, 0, 
                    Convert.ToInt32(player.rectWidth), Convert.ToInt32(player.rectHeight));
                player.rectHeight += 0.08f;
                player.rectWidth +=  0.08f;
                //Program.bufferedGraphics = context.Allocate(Program.graphics, new Rectangle(0, 0, 320,200));
                bufferedGraphics.Graphics.FillRectangle(Brushes.Green, 0, 0, Convert.ToInt32(player.rectWidth),
            Convert.ToInt32(player.rectHeight));
                tempWidth = player.rectWidth;
            }
            else
            {
                bufferedGraphics.Graphics.FillRectangle(Brushes.Green, 0, 0, Convert.ToInt32(player.rectWidth),
         Convert.ToInt32(player.rectHeight));
            }
            Program.player.DrawPlayer(Program.bufferedGraphics.Graphics, Brushes.Blue); //draw player controlled cube
            Program.bufferedGraphics.Render(Program.graphics); //finally render on screen

        }
    }
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr GetDC(IntPtr hWnd);
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    static extern short GetKeyState(int nVirtKey);
}
class Player //detect input and set player size and it's movement
{
    const int LEFT = 0x25;
    const int UP = 0x26;
    const int RIGHT = 0x27;
    const int DOWN = 0x28;
    const int G = 0x47;
    public float rectWidth = 200, rectHeight = 200;
    public float x;
    public float y;
    public Player()
    {
        this.x = 0;
        this.y = 0;
    }
    public void DoMove()
    {

        if ((GetKeyState(LEFT) | 0x8000) > 0 && this.x < rectWidth-10)
        {
            this.x += 0.1f;
        }
        if ((GetKeyState(RIGHT) | 0x8000) > 0 && this.x > 0)
        {
            this.x -= 0.1f;
        }
        if ((GetKeyState(UP) | 0x8000) > 0 )
        {
            this.y += 0.1f;
        }
        if ((GetKeyState(DOWN) | 0x8000) > 0 && this.y > 0)
        {
            this.y -= 0.1f;
        }
    }
    public void DrawPlayer(Graphics g, Brush color)
    {
        g.FillRectangle(color, this.x , this.y , 20, 20);
    }
    public void  ResizeScreen(out SByte value)
    {
        if ((GetKeyState(G) | 0x8000) < 0)
        {
            value = 1;
        }
        else if ((GetKeyState(0x48) | 0x8000) < 0)
        {
            value = -1;
        }
        else
        {
            value = 0;
        }
    }
    [DllImport("user32.dll")]
    static extern short GetKeyState(int nVirtKey);

}
class Collision //used for colliding with other objects and world boundaries
{
    public struct WorldEdges
    {
        public int leftBorder;
        public int rightBorder;
        public int topBorder;
        public int bottomBorder;
    }
     public WorldEdges worldEdges;


}

1 个答案:

答案 0 :(得分:0)

毫不奇怪,内存消耗增加,GC也参与其中。你有一个无限循环,不断分配一个大缓冲区(你的bufferedGraphics),使用它,然后让它挂起。你不仅疯狂地消耗记忆,而且还没有丢弃一次性物品。

BufferedGraphics类实现IDisposable interface,这意味着当您使用它时,您应该调用Dispose方法。这样做很可能会减轻很多记忆压力。它不会消除记忆压力,但应该稍微缓解一下。

您可能还想研究一次分配bufferedGraphics个对象并重新使用它的可能性。我对BufferedGraphics不够熟悉,所以我不能说这是否合理。但是如果你能做到这一点,那么减少GC对你的程序的影响应该有很长的路要走。

最后,你真的需要这个在while (true)循环中全速运行吗?如果您可以在计时器上执行此操作,例如每20或50毫秒一次,则可以减少CPU和内存的负载。