ArgumentException&进程内存在C#中不断增加

时间:2017-02-02 17:16:51

标签: c# visual-studio-2015 argumentexception

我已经编写并修改了经典蛇游戏的源代码。随着水平的增加,产生更多的苹果(例如1级将生成1个苹果,2级将生成2个苹果,依此类推。)当我达到5级时,正在生成5个苹果,以及我的大量增加进程内存,从400MB到2GB。这就是弹出“ArgumentException”错误并且游戏崩溃的地方。很抱歉我的编码不好,因为我还在学习。

错误显示在我的draw()方法中,我每500ms调用一次以刷新电路板。

Board.cs中的draw()方法发生错误

public void draw(Position p, Image pic)
    {
        squares[p.getRowNo(), p.getColNo()].Image = pic;
    }
form1.cs中的

刷新方法

private void refresh(Object myObject, EventArgs myEventArgs)
    {
        mySnake.move(mode); //Move the snake based on mode

        mainBoard.draw();
        apples.draw();  //<----- draw apples
        mySnake.draw();

        //increment the duration by amount of time that has passed
        duration += speed;
        timerLBL.Text = Convert.ToString(duration / 1000); //Show time passed


        //Check if snake is biting itself. If so, call GameOver.
        if (mySnake.checkEatItself() == true)
        {
            GameOver();
        }
        else if (apples.checkIFSnakeHeadEatApple( mySnake.getHeadPosition()) == true)
        {
            score += apples.eatAppleAtPostion(mySnake.getHeadPosition());

            scoreLBL.Text = Convert.ToString(score);


            if (apples.noMoreApples() == true)
            {
                EatenAllApple();
                clock.Stop();
                level++;
                gotoNextLevel(level);
                MessageBox.Show("Press the start button to go to Level " + level, "Congrats");
            }
            else
            {
                //Length the snake and continue with the Game
                mySnake.extendBody();
            }
        }
    }

Overal Board.cs

class Board
{
    int maxRow = 10, maxCol = 20;       //Max 10 rows, and 20 columns in the board
    int squareSize = 30;                //Each square is 30px by 30px

    PictureBox[,] squares;

    public Board(Form mainForm)
    {
        squares = new PictureBox[maxRow, maxCol];
        for (int row = 0; row < maxRow; row++)
        {
            for (int col = 0; col < maxCol; col++)
            {
                squares[row, col] = new PictureBox();
                squares[row, col].Location = new Point(col * squareSize, row * squareSize);
                squares[row, col].Height = squareSize;
                squares[row, col].Width = squareSize;
                squares[row, col].SizeMode = PictureBoxSizeMode.StretchImage;
                squares[row, col].BackColor = Color.Black;
                squares[row, col].BorderStyle = BorderStyle.FixedSingle;

                mainForm.Controls["boardPanel"].Controls.Add(squares[row, col]);
            }
        }
        mainForm.Controls["controlPanel"].Location = new Point(mainForm.Controls["boardPanel"].Location.X, mainForm.Controls["boardPanel"].Location.Y + mainForm.Controls["boardPanel"].Height + 20);
    }

    //setter
    public void setMaxColNo(int x)
    {
        maxCol = x;
    }

    public void setMaxRowNo(int x)
    {
        maxRow = x;
    }
    //getter
    public int getMaxColNo()
    {
        return maxCol-1; //Last Column No is 19, not 20
    }

    public int getMaxRowNo()
    {
        return maxRow-1; //Last Row No is 9, not 10
    }

    public int getMinColNo()
    {
        return 0;       // 0 is the smallest Col number of the board
    }

    public int getMinRowNo()
    {
        return 0;       // 0 is the smallest Row number of the board
    }

    public void draw()
    {
        for (int row = 0; row < maxRow; row++)
        {
            for (int col = 0; col < maxCol; col++)
            {
                squares[row, col].Image = null ;
            }
        }
    }

    public void draw(Position p, Image pic)
    {
        squares[p.getRowNo(), p.getColNo()].Image = pic;
    }
}

Rewards.cs(根据@AxelWass的要求)

class Rewards
{
    List<Position> appleList;
    Board mainBoard;

    public Rewards(int size, Board mainBoard)
    {
        this.mainBoard = mainBoard;
        appleList = new List<Position>();
        for (int i=0;i< size;i++)
        {
            int rowNo, colNo;

            //Generate an apple at random position but not duplicated
            do
            {
                //Generate a random number between 1 and MaxRowNo
                rowNo = (new Random()).Next(1, mainBoard.getMaxRowNo()+1);

                //Generate a random number between 1 and MaxColNo
                colNo = (new Random()).Next(1, mainBoard.getMaxColNo()+1);

            } while (isDuplicate(rowNo, colNo) == true);

            appleList.Add(new Position(rowNo, colNo));
        }
    }

    private Boolean isDuplicate(int row, int col)
    {
        Boolean result = false;

        for (int i=0;i< appleList.Count;i++)
        {
            if (appleList[i].getRowNo() == row && appleList[i].getColNo() == col)
                result = true;
        }

        return result;
    }

    public void draw()
    {
        for (int i = 0; i < appleList.Count; i++)
        {
            mainBoard.draw(appleList[i], Properties.Resources.apple);
        }     
    }

    public Boolean checkIFSnakeHeadEatApple(Position snakeHead)
    {
        Boolean result = false;

        for (int i = 0; i < appleList.Count; i++)
        {
            if (snakeHead.getRowNo() == appleList[i].getRowNo() && snakeHead.getColNo() == appleList[i].getColNo())
                result = true;
        }
        return result;
    }

    public Boolean checkIFSnakeEatApple(Position snakeHead)
    {
        Boolean result = false;

        for (int i = 0; i < appleList.Count; i++)
        {
            if (snakeHead.getRowNo() == appleList[i].getRowNo() && snakeHead.getColNo() == appleList[i].getColNo())
                result = true;
        }
        return result;
    }

    public int eatAppleAtPostion(Position p)
    {
        for (int i = 0; i < appleList.Count; i++)
        {
            if (p.getRowNo() == appleList[i].getRowNo() && p.getColNo() == appleList[i].getColNo())
                appleList.RemoveAt(i);
            //snakeEatApple();
        }


        return 50;  //50 points per apple
    }

    public Boolean noMoreApples()
    {
        if (appleList.Count > 0)
            return false;

        else
            return true;

    }

    /*public void snakeEatApple()
    {
        System.Media.SoundPlayer EatenApple = new System.Media.SoundPlayer(Properties.Resources.Eating_Apple);
        EatenApple.Play();
    }*/


}

1 个答案:

答案 0 :(得分:4)

   mainBoard.draw(appleList[i], Properties.Resources.apple);

这是问题陈述。 VS中的资源设计师设计得不是很好,违反了微软自己的编码指南。根本不明显的是apple属性每次使用它时都会创建一个新的Bitmap对象。由于它位于一个循环中,在一个本身将经常被调用的方法中,代码会生成一个 lot 的位图对象。

Bitmap是一个一次性类。不处理它通常很麻烦,它是一个非常小的包装类,可以使用大量的非托管内存。如果垃圾收集器没有经常运行以便终结器可以运行,程序的内存使用量可以非常快地运行。

解决方法是仅使用属性。将它存储在类的字段中(在方法之外):

  Bitmap apple = Properties.Resources.apple;

修正声明:

  mainBoard.draw(appleList[i], apple);

如果你穿过你的T并点缀你的话,那么当表格关闭时你就把它丢弃了:

  private void Form1_FormClosed(object sender, FormClosedEventArgs e) {
      apple.Dispose();
  }

这是一个很好的习惯,虽然这可能是不必要的,因为你的程序可能会在用户关闭窗口时结束。