Rohit
Rohit

Reputation: 1550

Should I dispose local class variables?

I have a legacy application where I am getting OutOfMemory exception time to time. I am trying to debug and fix the issue. One of the option I am thinking is to use the Dispose() method. I know that any object implementing the IDisposable interface will let me call the Dispose() method on it but will it also help freeing up resources to set the class level variables to null? like ArrayList or Hashtable?

I did search on internet and found a few posts but got a bit confused whether to null objects or not.

Code I am trying

public class RepET : base_entitlement, IDisposable
{
    #region Public Member Variables
    public const int ENTITLEMENT_TYPE = 7;
    public string table = "acc_rep";
    public ArrayList country_list;
    public Hashtable data;
    public ArrayList survey_dates;
    public ArrayList city_list;
    public Dictionary<string, Dictionary<string, string>> cityData;
    public Dictionary<string, Dictionary<string, string>> reportCity_list;
    public RepET(string entId)
    {
        if (id != "0")
        {
            id = entId;
            // if we cant load the metadata then load the full records & build the metadata

            if (!LoadFromMetaDb(id, ENTITLEMENT_TYPE))
            {
                if (this.load_entitlements())
                {
                    serialize_to_metadb(this, ENTITLEMENT_TYPE);
                }
            }
        }
    }
    #endregion

    public bool load_entitlements()
    {
        //  loads this entitlement from the metadata
        this.data = new Hashtable();
        this.survey_dates = new ArrayList();
        this.city_list = new ArrayList();
        //SqlQueries.ProcessingStarted(id);
        var sdates = SqlQueries.GetNewestSurveyByET(this.table, id, "acc_rep");

        if (sdates.Count == 0) return false;
        else
        {
            //delete ent 4 if already exist as its regenerated here
            check_EntFile_Created(id, Constants.ENTITLEMENT_TYPE_RP.ToString(), true);
            o_report_entitlements = new report_entitlements(id);

            reportCity_list = new Dictionary<string, Dictionary<string, string>>();
            foreach (string sd in sdates)
            {
                ent_by_survey_date(sd.Trim(), true);
                this.survey_dates.Add(sd.Trim());
            }
            o_report_entitlements.serialize_to_metadb(o_report_entitlements, Constants.ENTITLEMENT_TYPE_RP);

            return true;
        }
    }

    public bool ent_by_survey_date(string survey_date, bool modify_report_entitlements = false)
    {

        //if (modify_report_entitlements) {
        //    ArrayList countryArray;
        //}

        var dt = SqlQueries.Ent_by_survey_date(table, id, survey_date, "acc");
        if (dt.Rows.Count == 0)
        {
            return false;
        }
        else
        {
            country_list = new ArrayList();
            city_list = new ArrayList();

            Dictionary<string, ArrayList> countryCodes = new Dictionary<string, ArrayList>();

            foreach (DataRow row in dt.Rows)
            {
                string current_city_code = row["city_code"].ToString().Trim();
                string current_report_type = row["report_type"].ToString().Trim();

                if (!string.IsNullOrEmpty(current_city_code))
                {
                    Dictionary<string, string> currentCityReportList = new Dictionary<string, string>();
                    if (!reportCity_list.ContainsKey(survey_date))
                    {
                        reportCity_list[survey_date] = new Dictionary<string, string>();
                        reportCity_list[survey_date].Add(current_city_code, current_report_type);
                    }
                    else if (reportCity_list != null && reportCity_list.ContainsKey(survey_date) && !reportCity_list[survey_date].ContainsKey(current_city_code))
                    {
                        reportCity_list[survey_date].Add(current_city_code, current_report_type);
                    }

                    if (modify_report_entitlements)
                    {

                        string current_country_code = get_country_code_by_city(current_city_code);

                        if (!country_list.Contains(current_country_code))
                        {
                            country_list.Add(current_country_code);
                            foreach (var item in ((System.Reflection.TypeInfo)(o_report_entitlements.GetType())).DeclaredFields)
                            {
                                if (item.Name == "data")
                                {
                                    Hashtable tempObj = (Hashtable)item.GetValue(o_report_entitlements);
                                    if (tempObj != null)
                                    {
                                        countryCodes = (Dictionary<string, ArrayList>)tempObj[id];
                                        if (countryCodes != null && !countryCodes.ContainsKey(current_country_code))
                                            this.o_report_entitlements.add_to_array(current_country_code, "ACC", "", ref countryCodes);
                                        else if (countryCodes != null && countryCodes.ContainsKey(current_country_code) && !countryCodes[current_country_code].Contains("ACC"))
                                            this.o_report_entitlements.add_to_array(current_country_code, "ACC", "", ref countryCodes);
                                        else if (!countryCodes.ContainsKey(current_country_code))
                                            this.o_report_entitlements.add_to_array(current_country_code, "ACC", "", ref countryCodes);
                                    }
                                    else
                                    {
                                        if (countryCodes == null)
                                            countryCodes = new Dictionary<string, ArrayList>();
                                        this.o_report_entitlements.add_to_array(current_country_code, "ACC", "", ref countryCodes);
                                    }
                                }
                            }
                        }
                    }

                    if (!city_list.Contains(current_city_code))
                    {
                        city_list.Add(current_city_code);
                    }
                    if (!currentCityReportList.ContainsKey(current_city_code))
                    {
                        currentCityReportList.Add(current_city_code, current_report_type);
                    }
                    if (!data.ContainsKey(survey_date))
                    {
                        data[survey_date] = new Hashtable();
                    }
                    switch ((((Hashtable)this.data[survey_date])).GetType() == typeof(Dictionary<string, string>))
                    {
                        case true:
                            break;
                        case false:
                        default:
                            ((Hashtable)this.data[survey_date])[current_city_code] = new Dictionary<string, string>();
                            (((Dictionary<string, string>)((Hashtable)this.data[survey_date])[current_city_code])["city_code"]) = current_city_code;
                            //(((Dictionary<string, string>)((Hashtable)this.data[survey_date])[current_city_code])["city_code"])


                            //(((Dictionary<string, ArrayList>)((Hashtable)this.data[survey_date])[current_city_code])["report_type"]) = new ArrayList();
                            (((Dictionary<string, string>)((Hashtable)this.data[survey_date])[current_city_code])["report_type"]) = current_report_type;
                            //((Dictionary<string, string>)((Hashtable)this.data[survey_date])[current_city_code])["report_type"] = current_report_type;
                            break;
                    }
                }
            }
        }
        return true;
    }

    public string get_country_code_by_city(string city_code)
    {

        load_city_list();
        string returnItem = null;
        foreach (var item in cityData)
        {
            Dictionary<string, string> subItem = item.Value;
            if (subItem.ContainsKey(city_code))
            {
                returnItem += item.Key;
            }
        }
        return returnItem;
    }

    public bool load_city_list()
    {
        if (GlobalObjs.dtCityList.Rows.Count == 0)
            GlobalObjs.dtCityList = SqlQueries.LoadCityList();

        //var dt = SqlQueries.LoadCityList();
        if (GlobalObjs.dtCityList.Rows.Count == 0)
        {
            return false;
        }
        Dictionary<string, string> cityList = new Dictionary<string, string>();
        cityData = new Dictionary<string, Dictionary<string, string>>();
        foreach (DataRow row in GlobalObjs.dtCityList.Rows)
        {
            string Country_Code = row["Country_Code"].ToString().Trim();
            string City_Code = row["City_Code"].ToString().Trim();
            string City_Name = row["Name"].ToString().Trim();

            if (!cityData.ContainsKey(Country_Code))
            {
                cityData.Add(Country_Code, new Dictionary<string, string>());
            }

            Dictionary<string, string> tempList = cityData[Country_Code];
            if (!tempList.ContainsKey(City_Code))
            {
                tempList.Add(City_Code, City_Name);
                //cityList.Add(City_Code, City_Name);
                cityData[Country_Code] = tempList;
            }

        }
        return true;
    }



    // Flag: Has Dispose already been called?
    bool disposed = false;

    // Protected implementation of Dispose pattern.
    protected void Dispose(bool disposing)
    {
        if (disposed)
            return;

        if (disposing)
        {
            country_list = null;
            data = null;
            survey_dates = null;
            city_list = null;
            cityData = null;
            reportCity_list = null;
        }

        disposed = true;
    }
    public void Dispose()
    {
        Dispose(true);
    }
}

will this help with the memory exception?

Upvotes: 3

Views: 306

Answers (2)

Raju Dasupally
Raju Dasupally

Reputation: 174

As per the Microsoft documentation, the OutOfMemory exception is thrown when CLR can not allocate contiguous memory to perform an operation. In your case, since you are using Array-based data structures which may need contiguous memory allocation to a lot of data, hence you are getting the error.

- [https://learn.microsoft.com/en-us/dotnet/api/system.outofmemoryexception?view=netframework-4.8][1]

Instead of loading all the data at once into these array-based data structures, you may want to load as much less data as required for processing or try lazy loading

Upvotes: 2

Marc Gravell
Marc Gravell

Reputation: 1062855

The only time setting fields to null will make a difference to garbage collection is if you're still somehow leaving the RepET instance reachable in some way, in which case the real solution is: make sure that the RepET instance is no longer reachable! Setting the fields to null is papering over the real problem.

It is appropriate to use Dispose() to cascade things like connection and cmd, but... another part of me thinks the better approach there would be to not store them, i.e. obtain the connection on-demand, and keep cmd entirely local to where it is used; something like:

using (var conn = SomeHelper.CreateConnection())
{
    // your "cmd" code in here, via "using" - or
    // perhaps via "Dapper" and let it worry about that
}

The real trick, though, is finding what is holding the instance, if that is the real problem. Hard to comment without context, but: events and static caches are good places to start looking.

Upvotes: 4

Related Questions