在我的后台工作者完全消耗之前,我的静态属性上是否发生了垃圾收集?

时间:2014-12-30 21:11:11

标签: c# multithreading dictionary garbage-collection

我在网页中有一个后台工作程序来处理大文件导入。我有一个静态属性,包含我需要后台工作者访问的值字典。为了防止垃圾收集问题,我在将字典传递给后台工作程序时对其进行字符串化。问题是,在20次左右的时间里,“词典”似乎是垃圾收集之前它是字符串化的。

static readonly Dictionary<int, int> myDictionary = new Dictionary<int, int>();

//单击按钮时,我会触发后台工作程序

//假设后人,我在字典中填入了一个值列表,这些值在工作人员排队时存在。

protected void OnProcessClickHandler(object sender, EventArgs e)
{
    ThreadPool.QueueUserWorkItem(ProcessInBackground, new object[] { 
        DictionaryIntIntToCsv(myDictionary)
        });
}

//后台进程示例

private void ProcessInBackground(object state)
{
    object[] parms = state as object[];
    if (parms != null && parms.Length > 0)
    {
        var MyNewDictionary = DictionaryIntIntFromCsv(parms[0] as string);
        //... Doing something with the Dictionary
    }

}

//这是我用来字典化字符串的一些辅助方法。您可以忽略这些,除非您认为它们与手头的问题有关。

public static Dictionary<int, int> DictionaryIntIntFromCsv(string csv)
{
        var dictionary = new Dictionary<int, int>();

        foreach (var pair in csv.Split(','))
        {
            var arrNameValue = pair.Split(':');

            if (arrNameValue.Count() != 2) continue;

            var key = 0;
            var val = 0;

            int.TryParse(arrNameValue[0], out key);
            int.TryParse(arrNameValue[1], out val);

            if (key > 0 && val > 0)
            {
                dictionary.Add(key, val);
            }
        }

        return dictionary;
}

public static string DictionaryIntIntToCsv(Dictionary<int, int> dictionary)
{
        var str = "";

        foreach (var key in dictionary.Keys)
        {
            var value = 0;
            dictionary.TryGetValue(key, out value);

            if (key == 0 || value == 0) continue;

            var item = key + ":" + value;
            str += (item + ",");
        }

        return str;
}

我知道垃圾收集存在问题。我的理论有时主线程完成,垃圾收集在后台工作者有机会对字典进行字符串化之前运行。如果我在排队后台工作者之前对字典进行字符串化,我是否可以正确地假设我可以避免垃圾收集问题?像这样:

protected void OnProcessClickHandler(object sender, EventArgs e)
{
    var MyString = DictionaryIntIntToCsv(MyDictionary);
    ThreadPool.QueueUserWorkItem(ProcessInBackground, new object[] { 
        MyString
        });
}

注意:该页面是交互式的,在关闭后台工作程序之前会进行多次回发。

3 个答案:

答案 0 :(得分:1)

在这个问题中确实存在很多错误信息和奇怪的实现,以至于如果不进一步澄清就无法真正回答它。

是什么让你相信字典会在你“字母化”之后被收集?您实际使用ProcessInBackground()方法中的字典值做了什么?处理实际上是否比无条件地将字典序列化和反序列化string更昂贵?如果是这样,为什么有背景工作者被使用?为什么字符串在对象数组中传入而不是简单地传递给字符串本身?在这一点上,为什么字典会被序列化,是否有任何好的理由不能直接作为state参数传递?

答案 1 :(得分:0)

您可能在页面加载时初始化该属性。对属性的引用与页面加载时存在的页面实例相关联。在服务器向您发送初始页面后,该类符合垃圾回收的条件。

我相信您看到用户在页面上进行回发所需的时间与服务器收集该类的第一个实例所需的时间之间的竞争条件。

如果属性是非静态的,则回发时不会出现值。但是,由于它是一个静态属性,它将存在于内存中,直到垃圾收集器清理它。

答案 2 :(得分:-1)

在这里,您可以使用字典创建一个局部变量:

if (parms != null && parms.Length > 0)
{
    var MyNewDictionary = DictionaryIntIntFromCsv(parms[0] as string);
}

以上不以任何方式影响以下内容。您的代码中没有其他地方填充静态字段MyDictionary

上面的局部变量与您在此处的下方静态字段完全分开,因此上述分配不会以任何方式影响以下属性:

static readonly Dictionary<int, int> MyDictionary = new Dictionary<int, int>();