Zignd
Zignd

Reputation: 7025

Tips on releasing memory resources in C#

Could someone give me some tips related with release resources (memory resources)? I'm just a student and I'm building a system to an hypothetical small market, and during the testing of the option that add new products to cart, I discovered - using the Task Manager - that something is holding the resources, because the memory used by the program during debugging is increased in some bytes after every time I click on a specific button.

I'd like to know what I'm doing wrong, I also used dispose to release the resources used to connect with the database. Please help me, you don't have to code anything for me, just explain me what else should I release.

The button I'm referring to above is the buttonAdicionar it's event is at, buttonAdicionar_Click.

Here is the code at pastebin if you could take a look: 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;
        }
    }
}

Thanks.

Upvotes: 2

Views: 256

Answers (2)

Samjongenelen
Samjongenelen

Reputation: 401

My best guess would be by starting to use the using tags in C#

instead of

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

you should try:

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

Also, make your buttons so that its not calling DB injecting code directly, but use a Control class.

Eg on

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

and in your control class the following method:

controlClass :class
{
  //make singleton?

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

This way you exactly know when you're using what. Your IDE, like Visual Studio, might help you relocate code for better performance, based on tips form the compiler.

Also, as a general tip, try to read up on Design Patterns. these patterns aren't limited to C# so it's a nice to know / must know later on.

Upvotes: 2

Tommy Grovnes
Tommy Grovnes

Reputation: 4156

You are not doing anything inherently wrong, as a quick test you might want to change the order when you are closing/disposing leaving the command and connection for last.

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

Not sure this will fix your problem, if you adapt using() as suggested elsewhere you will get the right order automatically.

Another thing I noticed is that you use DataAdapter and DataTable but they don't really add any value, these two just add unnecessary memory overhead, try using DataReader instead. Example with using() and 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;
    }
  }
}

Upvotes: 2

Related Questions