2

有人可以给我一些与释放资源(内存资源)相关的提示吗?我只是一名学生,我正在为一个假设的小市场构建一个系统,在测试将新产品添加到购物车的选项期间,我发现 - 使用任务管理器 - 某些东西正在持有资源,因为每次单击特定按钮后,程序在调试期间使用的内存都会增加一些字节。

我想知道我做错了什么,我也使用 dispose 来释放用于连接数据库的资源。请帮助我,您不必为我编写任何代码,只需解释我还应该发布什么。

我上面提到的按钮是buttonAdicionar它的事件在, buttonAdicionar_Click

如果您可以看一下,这是 pastebin 的代码:pastebin.com/CdJbJAqc

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using MySql.Data.MySqlClient;

namespace Projeto_TCC
{
    public partial class FormCaixa : Form
    {
        #region Campos
        // const string CONNECTION_STRING = "server=localhost;uid=root;pwd=root;database=Projeto_TCC";
        private string mensagemDeSaida = "finalizar da aplicação";
        private int item = 0;
        private double totalVenda = 0.0;
        #endregion

        #region Método construtor
        public FormCaixa()
        {
            InitializeComponent();
        }
        #endregion

        #region Evento Click do ToolStrip Encerrar sessão
        private void encerrarSessãoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DialogResult = DialogResult.Yes;
            mensagemDeSaida = "encerrar esta sessão";
            this.Close();
        }
        #endregion

        #region Evento Click do ToolStrip Sair
        private void sairToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }
        #endregion

        #region Evento Click do ToolStrip Sobre
        private void sobreToolStripMenuItem_Click(object sender, EventArgs e)
        {
            new AboutBoxProjeto().ShowDialog(); // Isso é uma boa prática?
        }
        #endregion

        #region Evento FormClosing do FormCaixa
        private void FormCaixa_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (MessageBox.Show("Deseja " + mensagemDeSaida + "?", "Caixa", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
                e.Cancel = true;

            mensagemDeSaida = "finalizar da aplicação";
        }
        #endregion

        #region Evento Click do Button Adicionar
        private void buttonAdicionar_Click(object sender, EventArgs e)
        {
            // Prepara a conexão com o DB
            MySqlConnection con = new MySqlConnection(Properties.Settings.Default.ConnectionString);

            // Objetos utilizado para a realização de alguns processos
            MySqlDataAdapter da = new MySqlDataAdapter();
            DataTable dt = new DataTable();

            // Prepara o comando em SQL que retorná os dados sobre o item a ser adicionado à lista
            MySqlCommand cmd = new MySqlCommand("SELECT codigo, descricao, unidMedida, vlUnitario FROM tabEstoque WHERE codBar = @codBar;", con);
            cmd.Parameters.Add("@codBar", MySqlDbType.VarChar).Value = textBoxCodBarras.Text;

            try
            {
                // Abre a conexão e executa o comando em SQL
                con.Open();
                da.SelectCommand = cmd;
                da.SelectCommand.ExecuteNonQuery();
                da.Fill(dt);

                // Caso haja alguma linha no DataSet ds então existe um produto com o codigo de barra procurado no banco de dados
                if (dt.Rows.Count == 1)
                {
                    bool itemIgual = false;
                    int rowIndex = 0;

                    // Passa por todas as linhas da lista de compras para verificar se existe outro item igual
                    foreach (DataGridViewRow dgvListaRow in dataGridViewLista.Rows)
                    {
                        // Verifica se o produto da linha da lista de compra é o mesmo do código de barras
                        if (dgvListaRow.Cells[1].FormattedValue.ToString() == dt.Rows[0][0].ToString())
                        {
                            // Verifica se estão tentando vender uma certa quantidade de um produto que esteja acima da quantidade do mesmo no estoque
                            if (!this.VerificarSeExcede(Convert.ToInt32(dgvListaRow.Cells[1].FormattedValue), Convert.ToInt32(dgvListaRow.Cells[3].FormattedValue) + 1))
                            {
                                // Adiciona mais um na quantidade do item na lista de compra
                                dgvListaRow.Cells[3].Value = Convert.ToInt32(dgvListaRow.Cells[3].FormattedValue) + 1;
                                // Multiplica o VL. ITEM. pela nova quantidade e armazena o resultado em VL. ITEM
                                dgvListaRow.Cells[6].Value = String.Format("{0:f}",
                                    (Convert.ToDouble(dgvListaRow.Cells[3].Value) * Convert.ToDouble(dgvListaRow.Cells[5].Value)));

                                // Adiciona o valor do produto ao valor total da venda
                                totalVenda += Convert.ToDouble(dgvListaRow.Cells[5].Value);
                            }
                            else
                            {
                                MessageBox.Show("Ocorreu a tentativa de vender uma certa quantidade deste produto que excede a quantidade do mesmo no estoque.", "Caixa", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            }

                            itemIgual = true; // Evita que o if abaixo seja executado
                            break; // Sai do loop para econimizar tempo no processamento
                        }

                        rowIndex++;
                    }

                    // Caso o item não seja igual a nenhum outro na lista ele é adicionado à lista
                    if (!itemIgual)
                    {
                        // Verifica se estão tentando vender uma certa quantidade de um produto que esteja acima da quantidade do mesmo no estoque
                        if (!this.VerificarSeExcede(Convert.ToInt32(dt.Rows[0][0].ToString()), 1))
                        {
                            dataGridViewLista.Rows.Add(
                                ++item,                     // ITEM
                                dt.Rows[0][0],    // CÓDIGO
                                dt.Rows[0][1],    // DESCRIÇÃO
                                1,                          // QTD.
                                dt.Rows[0][2],    // UN.
                                dt.Rows[0][3],    // VL. UNIT.
                                dt.Rows[0][3]);   // VL. ITEM.

                            // Adiciona o valor do produto ao valor total da venda
                            totalVenda += Convert.ToDouble(dt.Rows[0][3].ToString());
                        }
                        else
                        {
                            MessageBox.Show("Ocorreu a tentativa de vender uma certa quantidade deste produto que excede a quantidade do mesmo no estoque.", "Caixa", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        }
                    }

                    // Atualiza a label que o exibe o total da venda
                    labelTotal.Text = String.Format("Total: {0:c}", totalVenda);
                }
                else // Mensagem exibida caso a cosulta nao retorne alguma coisa
                {
                    MessageBox.Show("Este item não consta no banco de dados.", "Caixa", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            catch (MySqlException ex)
            {
                MessageBox.Show("Ocorreu um erro durante a comunicação com o banco de dados.\n\n" + ex.Message, "Caixa", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                con.Close(); // Fecha a conexão
                // Liberam os recursos/espaços ocupados na memória
                da.Dispose();
                dt.Dispose();
                cmd.Dispose();
            }
            //textBoxCodBarras.Clear();
            //textBoxCodBarras.Focus();
        }
        #endregion

        private bool VerificarSeExcede(int codProd, int quantItem)
        {
            MySqlConnection con = new MySqlConnection(Properties.Settings.Default.ConnectionString);
            MySqlCommand cmd = new MySqlCommand("SELECT codigo, quantidade FROM tabestoque WHERE codigo = @codProd", con);
            cmd.Parameters.Add("@codProd", MySqlDbType.Int32).Value = codProd;
            MySqlDataAdapter da = new MySqlDataAdapter(cmd);
            DataTable dt = new DataTable();

            con.Open();
            da.SelectCommand.ExecuteNonQuery();
            da.Fill(dt);
            int quantDB = Convert.ToInt32(dt.Rows[0][1]);

            con.Close();
            cmd.Dispose();
            da.Dispose();
            dt.Dispose();

            // Verifica se a quantidade do produto no banco de dados é >= que a quantidade do item na lista
            if (quantDB >= quantItem)
                return false;
            else
                return true;
        }
    }
}

谢谢。

4

2 回答 2

2

您并没有做任何本质上的错误,作为一个快速测试,您可能希望在关闭/处置时更改顺序,最后留下命令和连接。

da.Dispose();
dt.Dispose();
cmd.Dispose();
con.Close(); 

不确定这是否会解决您的问题,如果您按照其他地方的建议调整 using() ,您将自动获得正确的顺序。

我注意到的另一件事是您使用 DataAdapter 和 DataTable 但它们并没有真正增加任何价值,这两个只是增加了不必要的内存开销,请尝试使用 DataReader。using() 和 DataReader 的示例:

private bool VerificarSeExcede(int codProd, int quantItem)
{
  using(var con = new MySqlConnection(Properties.Settings.Default.ConnectionString)) 
  {
    using(var cmd = new MySqlCommand("SELECT codigo, quantidade FROM tabestoque WHERE codigo = @codProd", con)) 
    {
      cmd.Parameters.Add("@codProd", MySqlDbType.Int32).Value = codProd;
      con.open();

      using(var reader = cmd.ExecuteReader()) 
      {
        if(reader == null) 
           return false;  

        reader.Read();
        var quantDB = reader.GetInt32(1);

        // Verifica se a quantidade do produto no banco de dados é >= que a quantidade do item na lista
        if (quantDB >= quantItem)
          return false;
        else
          return true;
    }
  }
}
于 2013-05-07T13:46:55.630 回答
2

我最好的猜测是开始使用usingC# 中的标签

代替

myConnection = new connection(connectionString);
myConnection.open();
//do something with connection
myconnection.close();

你应该试试:

using (connection myConnection = new connection(connectionstring))
{
 //do something with myConnection
}

另外,制作您的按钮,使其不直接调用数据库注入代码,而是使用 Control 类。

例如开

`private void buttonAdicionar_Click(object sender, EventArgs e)`
        {
            controlClass.DoSomethingNow()
        }

并在您的控件类中使用以下方法:

controlClass :class
{
  //make singleton?

    public void DoSomethingNow()
            {
              using (connection myConnection = new connection(connectionstring))
              { 
                //do something with myConnection 
              }
            }
 }

这样您就可以确切地知道何时使用什么。您的 IDE(如 Visual Studio)可能会根据编译器的提示帮助您重新定位代码以获得更好的性能。

另外,作为一般提示,请尝试阅读Design Patterns。这些模式不仅限于 C#,因此很高兴知道/以后必须知道。

于 2013-05-07T13:01:10.470 回答