使用linq将位图放置在数组中 [英] dispose bitmap in an array using linq

查看:59
本文介绍了使用linq将位图放置在数组中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有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.

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

2个问题:

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

解决方案

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

让我们以一个朴素的例子为例...如果可见图像,它将保留在内存中,否则将其卸载.

(这并不理想,因为每次滚动时都需要从磁盘上重新获取图像,但这证明了这种方法)

比方说,我们有一个功能,可以确定查看哪些图像并返回路径列表(可以等效地是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);
    }
}

您将必须进行一些调整,以找出保留在缓存中的数量/提前加载映像的最有效点,从而在目标硬件上实现性能/响应能力的最佳平衡./p>

此外,并不是真的需要滚动执行此操作....只是半定期的,但这是出于演示目的而插入的一个方便点.根据您选择的策略,计时器或其他方法可能更合适.

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

检查对象是否被引用(而不是检查对象是否已放置)(它是否为null/键是否存在/列表是否为空等)

在上面这是通过处理然后从字典中删除来解决的.

I have an array of 3500 bitmaps. These bitmaps are displayed on the screen (a screen can display 12) and more are loaded while the vertical scroll bar is going down. At some point, i would like to release these images from memory and i'd like to know if Linq can help : What i tried :

Declaration :

    imageCache = new Bitmap[someCountWithaResultOf3500];

The imageCache gets loaded by images and then at some point i would like to dispose a few (from the beginning to 200 before the current one). Id tells me the first image displayed.

Function

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

the lowlimit is the Max of 0 and the id -200 of the image displayed.

When i reach the lowlimit, the screen becomes black, the images disappear (in debug mode, i had the lowlimit at 4)

2 questions :

  • in the where clause, i would like to filter on non disposed bitmaps, how to do it (my clause x.j !=null doesnt work )
  • Is the Dispose at the foreach supposed to work ?

解决方案

The key question is how to determine when images can be unloaded.

Let's take a naive example... If an image is visible, it'll be kept in memory, otherwise unload it.

(This won't be ideal as any time you scroll, images need to be re-fetched from disk but it demonstrates the approach)

Let's say we have a function that determines which images are in view and returns a list of paths [could equally be IDs]....

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
}

So....

When someone changes the scroll position of your control

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

You're going to have to do some tuning to work out the sweet spot for how much to keep in the cache/how far in advance to load images to give an optimal balance of performance/responsiveness on your target hardware.

Also, doing this on scroll isn't really necessary.... Just semi-regularly, but it was a convenient point to hook into for demo purposes. Depending on the strategy you pick, a timer or some other approach might be more appropriate.

One point on determining if something is disposed... Don't. As soon as you dispose of an object, release all references to it. If you need a new one, you'll have to create it fresh anyway, so keep a reference to an unusable object is pointless.

Instead of checking if the object is disposed, check if you have an object referenced at all (is it null / does the key exist / is the list empty / etc)

This is handled above by disposing, then removing from the dictionary.

这篇关于使用linq将位图放置在数组中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆