簡體   English   中英

更新大列表時出現OutOfMemoryException?

[英]OutOfMemoryException when updating a large list?

我的清單很大,如果需要,我想覆蓋一個值。 為此,我創建了列表的兩個子集,這似乎給了我一個OutOfMemoryException 這是我的代碼段:

if (ownRG != "")
{
    List<string> maclist = ownRG.Split(',').ToList();
    List<IVFile> temp = powlist.Where(a => maclist.Contains(a.Machine)).ToList();
    powlist = powlist.Where(a => !maclist.Contains(a.Machine)).ToList(); // OOME Here
    temp.ForEach(a => { a.ReportingGroup = ownRG; });
    powlist.AddRange(temp);
} 

本質上,我將列表分為需要更新的部分和不需要更新的部分,然后執行更新並將列表放回原處。 這工作得很好了小名單,但有一個打破OutOfMemoryException中的第三行if一個大名單。 我可以提高效率嗎?

注意
powlist是大型列表(> 1m)。 maclist只有1到10之間,但即使有1個項目也會中斷。

解決您的問題

這是使用答案中的枚舉器代碼重新排列代碼的方法:

if (!string.IsNullOrEmpty(ownRG))
{
    var maclist = new CommaSeparatedStringEnumerable(str);
    var temp = powlist.Where(a => maclist.Contains(a.Machine));

    foreach (var p in temp)
    {
        p.ReportingGroup = ownRG;
    }
} 
  • 您不應在代碼中使用ToList
  • 您無需從powlist刪除temp內容(無論如何您都在重新添加它們)

通過大逗號分隔的字符串流式傳輸

你可以遍歷列表中手動,而不是做你現在做什么,通過尋找,人物和記住最后一次的位置發現了一個和之前的一個。 這肯定會使您的應用程序正常工作,因為這樣就無需立即將整個集合存儲在內存中。

代碼示例:

var str = "aaa,bbb,ccc";
var previousComma = -1;
var currentComma = 0;

for (; (currentComma = str.IndexOf(',', previousComma + 1)) != -1; previousComma = currentComma)
{
    var currentItem = str.Substring(previousComma + 1, currentComma - previousComma - 1);
    Console.WriteLine(currentItem);
}
var lastItem = str.Substring(previousComma + 1);
Console.WriteLine(lastItem);

自定義迭代器

如果您想以一種不錯的方式“正確”地進行操作,甚至可以編寫一個自定義枚舉器:

public class CommaSeparatedStringEnumerator : IEnumerator<string>
{
    int previousComma = -1;
    int currentComma = -1;
    string bigString = null;
    bool atEnd = false;

    public CommaSeparatedStringEnumerator(string s)
    {
        if (s == null)
            throw new ArgumentNullException("s");

        bigString = s;
        this.Reset();
    }

    public string Current { get; private set; }

    public void Dispose() { /* No need to do anything here */ }

    object IEnumerator.Current { get { return this.Current; } }

    public bool MoveNext()
    {
        if (atEnd)
            return false;

        atEnd = (currentComma = bigString.IndexOf(',', previousComma + 1)) == -1;

        if (!atEnd)
            Current = bigString.Substring(previousComma + 1, currentComma - previousComma - 1);
        else
            Current = bigString.Substring(previousComma + 1);

        previousComma = currentComma;
        return true;
    }

    public void Reset()
    {
        previousComma = -1;
        currentComma = -1;
        atEnd = false;
        this.Current = null;
    }
}

public class CommaSeparatedStringEnumerable : IEnumerable<string>
{
    string bigString = null;

    public CommaSeparatedStringEnumerable(string s)
    {
        if (s == null)
            throw new ArgumentNullException("s");

        bigString = s;
    }

    public IEnumerator<string> GetEnumerator()
    {
        return new CommaSeparatedStringEnumerator(bigString);
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}

然后,您可以像這樣迭代它:

var str = "aaa,bbb,ccc";
var enumerable = new CommaSeparatedStringEnumerable(str);

foreach (var item in enumerable)
{
    Console.WriteLine(item);
}

其他想法

我可以提高效率嗎?

是的你可以。 我建議使用更有效的數據格式(您可以根據需要瀏覽數據庫或XML,JSON等)。 如果您真的想使用逗號分隔的項目,請參見上面的代碼示例。

在循環中找到下一個','char。 取','和上一個','位置之間的子字符串。 在循環的末尾,保存對先前“,”位置(初始設置為0)的引用。 因此,您可以逐項解析項目,而不是一次解析所有項目。

無需從powlist創建一堆子列表並將其重建。 只需遍歷powlist並相應地更新ReportingGroup屬性。

var maclist = new HashSet<string>( ownRG.Split(',') );
foreach( var item in powlist) {
    if( maclist.Contains( item.Machine ) ){
        item.ReportingGroup = ownRG;
    }
}

由於這會更改powlist ,因此您不會分配任何額外的內存,也不會遇到OutOfMemoryException

您可以嘗試循環列表中的項目,但這會增加處理時間。

foreach(var item in powlist)
{
//do your opeartions
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM