大型数组中的内存泄漏 - 子类化 IList 会修复它吗?

发布于 2024-08-20 20:23:51 字数 664 浏览 5 评论 0原文

我需要提高应用程序的内存性能,但我发现存在内存碎片问题。

我读过 来自 Red Gate 的 Andrew Hunter 的关于大型对象的有趣文章,他推荐的解决方案之一是:

如果大型数据结构需要生存 很长一段时间,特别是如果 它们需要随着时间的推移而变大, 最好的方法就是 考虑使用或编写不同的 存储它们的数据结构。数组 最多可容纳约 10,000 个 元素在被放置之前 大对象堆,可能会导致 问题,所以一个非常有效的方法 存储 100,000 个条目可能是 存储 10 个数组,每个数组包含 10,000 元素:没有一个会出现在 大对象堆,因此没有碎片 会发生。这可以写成 一个 IList 子类,这将使它 易于透明地放入 替换现有代码。

我如何在我的代码中实现他的建议?

我的程序有一个非常复杂的形式(带有一个每次打开时都会留下残留内存的对象。我发现一个复杂的列表可能是罪魁祸首,我想实现他的建议看看是否它解决了这个问题。

I need to improve memory performance on my application and I could see that I have problems with memory fragmentation.

I've read an interesting article on large objects from Andrew Hunter of Red Gate, and one of the solutions he recommends is:

If large data structures need to live
for a long time, and especially if
they need to grow in size over time,
the best approach is simply to
consider using or writing a different
data structure to store them. Arrays
can contain up to around 10,000
elements before they are put on the
large object heap and can cause
problems, so a very effective way to
store 100,000 entries might be to
store 10 arrays each containing 10,000
elements: none will end up on the
large object heap so no fragmentation
will occur. This could be written as
an IList subclass, which would make it
easy to drop in transparently to
replace existing code.

How do I implement his suggestion in my code?

My program has a very complex form (with an object that leaves residual memory every time it opens. I found a complex list that may be the culprit, and I'd like to implement his suggestion to see if it fixes the issue.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

雪落纷纷 2024-08-27 20:23:51

使用 List 来实现这一点有什么问题吗?这只是 IList 的一个实现,您可以自己进行分区。但如果你想透明地做到这一点:

实现 IList (它只是一个接口,没有什么特别的。也许我不明白这个问题?)并通过所需大小的数组来支持它。然后,您的 Get() 会将 index / sizeOfArrays 作为包含所需项目的数组的索引,并返回第 index % sizeOfArrays 中的项目那个数组。


为了好玩,因为这是一个懒惰的星期五,我写了一些东西。注意:

  • 我没有测试它,
  • 我无法评论您引用的声明的正确性,这可能有助于避免内存碎片,我只是盲目地查看您的请求,
  • 我不知道 List 或任何其他集合是否已经足够聪明来做到这一点只是
  • 我做出了一些可能不适合您的决定(即,如果您现在使用数组,则不能盲目地将其放入代码中。例如,查看 Item 实现,尤其是 setter

也就是说,这是一个减少我周末前动机不足的起点,我给亲爱的读者(或OP)留下了一些有趣的方法作为练习..;-)

public class PartitionList<T> : IList<T> {
    private readonly int _maxCountPerList;
    private readonly IList<IList<T>> _lists;

    public PartitionList(int maxCountPerList) {
        _maxCountPerList = maxCountPerList;
        _lists = new List<IList<T>> { new List<T>() };
    }

    public IEnumerator<T> GetEnumerator() {
        return _lists.SelectMany(list => list).GetEnumerator();
    }

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

    public void Add(T item) {
        var lastList = _lists[_lists.Count - 1];
        if (lastList.Count == _maxCountPerList) {
            lastList = new List<T>();
            _lists.Add(lastList);
        }
        lastList.Add(item);
    }

    public void Clear() {
        while (_lists.Count > 1) _lists.RemoveAt(1);
        _lists[0].Clear();
    }

    public bool Contains(T item) {
        return _lists.Any(sublist => sublist.Contains(item));
    }

    public void CopyTo(T[] array, int arrayIndex) {
        // Homework
        throw new NotImplementedException();
    }

    public bool Remove(T item) {
        // Evil, Linq with sideeffects
        return _lists.Any(sublist => sublist.Remove(item));
    }

    public int Count {
        get { return _lists.Sum(subList => subList.Count); }
    }

    public bool IsReadOnly {
        get { return false; }
    }

    public int IndexOf(T item) {
        int index = _lists.Select((subList, i) => subList.IndexOf(item) * i).Max();
        return (index > -1) ? index : -1;
    }

    public void Insert(int index, T item) {
        // Homework
        throw new NotImplementedException();
    }

    public void RemoveAt(int index) {
        // Homework
        throw new NotImplementedException();
    }

    public T this[int index] {
        get {
            if (index >= _lists.Sum(subList => subList.Count)) {
                throw new IndexOutOfRangeException();
            }
            var list = _lists[index / _maxCountPerList];
            return list[index % _maxCountPerList];
        }
        set {
            if (index >= _lists.Sum(subList => subList.Count)) {
                throw new IndexOutOfRangeException();
            }
            var list = _lists[index / _maxCountPerList];
            list[index % _maxCountPerList] = value;
        }
    }
}

What's wrong with using List for that? That's nothing but an implementation of IList and you can do the partitioning yourself. But if you want to do it transparently:

Implement IList (it's just an interface, nothing special about it. Maybe I don't understand the question?) and back it up by arrays of your desired size. Your Get() would then take the index / sizeOfArrays as index of the array containing the desired item and return the index % sizeOfArraysth item in that array.


For fun, because it's a lazy friday, I wrote something up. Note:

  • I didn't test it
  • I cannot comment on the correctnes of your quoted claims that this might help avoiding memory fragmentation, I just blindly looked at your request
  • I don't know if List or any other collection is already smart enough to do just that
  • I made some decisions that might not be right for you (i.e. you cannot blindly drop this in your code if you're using arrays now. Look at the Item implementation, especially the setter, for example

That said, here's a starting point that reduced my pre-weekend motivational deficit. I left some interesting methods as exercise to the dear reader (or OP).. ;-)

public class PartitionList<T> : IList<T> {
    private readonly int _maxCountPerList;
    private readonly IList<IList<T>> _lists;

    public PartitionList(int maxCountPerList) {
        _maxCountPerList = maxCountPerList;
        _lists = new List<IList<T>> { new List<T>() };
    }

    public IEnumerator<T> GetEnumerator() {
        return _lists.SelectMany(list => list).GetEnumerator();
    }

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

    public void Add(T item) {
        var lastList = _lists[_lists.Count - 1];
        if (lastList.Count == _maxCountPerList) {
            lastList = new List<T>();
            _lists.Add(lastList);
        }
        lastList.Add(item);
    }

    public void Clear() {
        while (_lists.Count > 1) _lists.RemoveAt(1);
        _lists[0].Clear();
    }

    public bool Contains(T item) {
        return _lists.Any(sublist => sublist.Contains(item));
    }

    public void CopyTo(T[] array, int arrayIndex) {
        // Homework
        throw new NotImplementedException();
    }

    public bool Remove(T item) {
        // Evil, Linq with sideeffects
        return _lists.Any(sublist => sublist.Remove(item));
    }

    public int Count {
        get { return _lists.Sum(subList => subList.Count); }
    }

    public bool IsReadOnly {
        get { return false; }
    }

    public int IndexOf(T item) {
        int index = _lists.Select((subList, i) => subList.IndexOf(item) * i).Max();
        return (index > -1) ? index : -1;
    }

    public void Insert(int index, T item) {
        // Homework
        throw new NotImplementedException();
    }

    public void RemoveAt(int index) {
        // Homework
        throw new NotImplementedException();
    }

    public T this[int index] {
        get {
            if (index >= _lists.Sum(subList => subList.Count)) {
                throw new IndexOutOfRangeException();
            }
            var list = _lists[index / _maxCountPerList];
            return list[index % _maxCountPerList];
        }
        set {
            if (index >= _lists.Sum(subList => subList.Count)) {
                throw new IndexOutOfRangeException();
            }
            var list = _lists[index / _maxCountPerList];
            list[index % _maxCountPerList] = value;
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文