dispose bitmap in an array using linq

北慕城南 提交于 2020-06-28 08:34:17

问题


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 ?

回答1:


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.



来源:https://stackoverflow.com/questions/61602041/dispose-bitmap-in-an-array-using-linq

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!