【问题标题】:dispose bitmap in an array using linq使用 linq 在数组中处理位图
【发布时间】:2020-05-04 21:35:20
【问题描述】:

我有一个包含 3500 个位图的数组。这些位图显示在屏幕上(一个屏幕可以显示 12 个),当垂直滚动条向下时会加载更多位图。 在某些时候,我想从内存中释放这些图像,我想知道 Linq 是否可以提供帮助: 我尝试了什么:

声明:

    imageCache = new Bitmap[someCountWithaResultOf3500];

imageCache 由图像加载,然后在某些时候我想处理一些(从开始到当前图像之前的 200 个)。 Id 告诉我显示的第一张图片。

功能

imageCache.AsEnumerable()
                   .Select((s, j) => new { j, s })
                   .Where(x => (x.j > 0 && x.j < lowlimit && x.j != null))
                   .ToList().ForEach(x => Dispose());

lowlimit 是 0 的最大值和所显示图像的 id -200

当我达到下限时,屏幕变黑,图像消失(在调试模式下,我在 4 点有 lowlimit

2 个问题:

  • 在 where 子句中,我想过滤未处理的位图,怎么做(我的子句 x.j !=null 不起作用)
  • foreach 的 Dispose 是否应该工作?

【问题讨论】:

  • 1. x.j != null 并不意味着图像没有被释放,它意味着它不为空。如果您处置某些东西,它不会变为空。 2. 应该是ForEach(x =&gt; x.s.Dispose()); 除了其他一些问题: a) 你不需要打电话给AsEnumerable()。 b) 而不是s,您应该给属性一个更详细的名称,例如bitmap。 c) 我会使用像 foreach (var item in imageCache.Select(…).Where(…)) { item.s.Dispose(); } 这样的常规 foreach 语句来代替 ToList().ForEach(…),以避免分配一次性列表只是为了调用 ForEach 方法。
  • 你们的显示技术是什么?如果您在 WPF 或 UWP 中工作,则对此类工作有很好的支持。 | 3500 位图对于人工处理来说似乎太大了。 100 可能是一个更可能的限制。您必须减少任何更多内容,最好不要加载这些内容。
  • 如您指定的 WPF;这里有一些关于主题的东西:codeproject.com/Articles/34405/WPF-Data-Virtualization
  • @SebastienChemouny GPU 不重要,因为没有复杂的渲染。它主要是将所有这些图像(未压缩)放入 RAM 中。
  • 可能值得一提的是,这是stackoverflow.com/q/61574511/156755 的后续行动,以便为其他人提供一些背景信息。 (这是一个自定义的 Winforms 控件,您在短时间内看到大量图像,您正在使用 [x] 作为缓存,按需加载等...)

标签: c# winforms linq


【解决方案1】:

关键问题是如何确定何时可以卸载图像。

让我们举个简单的例子...如果图像可见,则将其保存在内存中,否则将其卸载。

(这并不理想,因为在您滚动时,需要从磁盘重新获取图像,但它演示了该方法)

假设我们有一个函数可以确定哪些图像在视图中并返回路径列表[同样可以是 ID]....

public List<string> GetVisibleImagePaths() {
    //Do something here to return a dozen or so paths that are visible.

    //Later refinement: Also include images a few either side of the current position for 
    //smoother scrolling
}

所以....

当有人改变你控件的滚动位置时

protected override void OnScroll(ScrollEventArgs se) {
    base.OnScroll(se);
    EvictFromCache();
}

private Dictionary<string, Bitmap> imageCache;

private void EvictFromCache() {
    var paths = GetVisibleImagePaths();
    // Now loop through all the keys in the cache and evict those not specifically requested
    // This is a naive approach to cache eviction. Perhaps you want to keep the last few dozen
    // in case the user reverses direction and scrolls back or .... Lots of options, but for now
    // we'll evict anything not in the list of paths we were given
    foreach (var expired in imageCache.Keys.Where(x => !paths.Contains(x)).ToList()) {
        //Dispose of the object, freeing up resources
        imageCache[expired].Dispose();

        //And now remove the reference to the disposed object
        imageCache.Remove(expired);
    }
}

您将不得不进行一些调整,以确定在缓存中保留多少/提前多长时间加载图像的最佳平衡点,以便在目标硬件上实现性能/响应能力的最佳平衡。

此外,在滚动上执行此操作并不是真正必要的......只是半定期,但它是一个方便的点,用于演示目的。根据您选择的策略,计时器或其他方法可能更合适。

关于确定是否处置某物的一点...不要。处置对象后,立即释放对它的所有引用。如果您需要一个新对象,无论如何您都必须重新创建它,因此保留对不可用对象的引用是没有意义的。

不是检查对象是否被释放,而是检查你是否有一个对象被引用(它是否为空/键是否存在/列表是否为空/等等)

上面的处理方法是处理,然后从字典中删除。

【讨论】:

  • 感谢 Basic(再次),令人难以置信的是,您的方法如此简单,同时又有效。我只需要修改一件事,foreach 没有工作,因为在删除时修改了集合并引发了异常(在最后添加ToList()。我还为空值添加了一个新过滤器以排除已处置或非处置创造价值:foreach (var expired in imageCache.Where(x =&gt; !paths.Contains(x.Key)).Where(x=&gt; x.Value !=null).Select(x=&gt; x.Key).ToList())
  • 很好地了解修改集合... 教我使用 IDE。至于其余的,不用担心......自从我有机会做任何 C# 以来已经有 5 年时间了(大约和我花时间回答的时间一样长),所以我正在寻找一些有点挑战性但速度很快的东西足以回答。最后一点......如果您的位图已被处理,则该键不应再在字典中。我的评论是错误的,因为从 dict 中删除与设置为 null [fixed] 一样好。关键是托管代码中不再有对对象的引用。这使您的逻辑更清晰
  • 哦,还有...一种清理“修改集合”问题的干净方法...在 for 循环中,在 linq 末尾添加 .ToList()...@987654326 @ 这样,它不是通过原始集合(缓存)的过滤版本工作,而是创建一个新的项目列表并迭代它。
  • 非常欢迎。最后一件事......如果这是我的项目,我会将缓存功能移动到一个新类中。只需使用 GetImage/EvictCache 方法和您需要的任何其他方法编写 ImageCache 类。这将所有缓存逻辑与表单分开,并允许您非常轻松地在其他地方重用它。 [“干净代码”口头禅的所有部分]。无论如何,一切顺利
  • 是的,我真的需要在清理代码方面做得更好......但好的一点,拥有一个“轻量级”表单实际上很好(一切都在课堂上)。再次感谢,我想我找到了最佳点,它很流畅,不占用内存,在滚动条和鼠标滚轮上工作,当我将鼠标移到图片上或单击它时,我现在可以专注于动作:) 再次感谢一堆,从没想过我会到达那里:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多