Должен ли я использовать локальные переменные класса? - PullRequest
3 голосов
/ 03 марта 2020

У меня есть устаревшее приложение, в котором время от времени я получаю OutOfMemory исключение. Я пытаюсь отладить и исправить проблему. Я думаю, что один из вариантов - использовать метод Dispose(). Я знаю, что любой объект, реализующий интерфейс IDisposable, позволит мне вызвать для него метод Dispose(), но поможет ли это высвободить ресурсы для установки переменных уровня класса null? как ArrayList или Hashtable?

Я выполнил поиск по inte rnet и нашел несколько сообщений, но немного запутался: null объекты или нет.

Код, который я пытаюсь

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);
    }
}

это поможет с исключением памяти?

Ответы [ 2 ]

4 голосов
/ 03 марта 2020

Поля времени, установленные на null, будут иметь значение только для сборки мусора, если вы все равно каким-то образом оставляете экземпляр RepET доступным, и в этом случае реальное решение: убедитесь, что RepET экземпляр больше недоступен! Установка полей на null - это реальная проблема.

Уместно использовать Dispose() для каскадирования таких вещей, как connection и cmd, но ... другая часть меня думает, что лучшим подходом было бы не хранить их , то есть получать соединение по требованию и сохранять cmd полностью локальным там, где оно используется; что-то вроде:

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

Реальный трюк, однако, заключается в том, чтобы найти то, что содержит экземпляр, , если , это реальная проблема. Трудно комментировать без контекста, но: кэш событий и событий c - это хорошее место для поиска.

2 голосов
/ 03 марта 2020

Согласно документации Microsoft, исключение OutOfMemory возникает, когда CLR не может выделить непрерывную память для выполнения операции. В вашем случае, поскольку вы используете структуры данных на основе массива, которым может потребоваться непрерывное выделение памяти для большого количества данных, следовательно, вы получаете ошибку.

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

Вместо того, чтобы загружать все данные сразу в эти структуры данных на основе массива, вы можете загрузить столько данных, сколько требуется для обработки, или попробовать отложенную загрузку

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...