假设我必须在某些控件上显示一些图形。但是根据某些条件会有三个图像切换。资源文件中添加了三个位图。
因此,我通过调用ResourceManager.GetObject来检索它们。
问题是,它应该是:
执行1)似乎会产生大量GC句柄。 希望知道2)的任何不良副作用。
非常感谢。
答案 0 :(得分:7)
每次调用GetObject
都会从程序集中读取图像并将其加载到Bitmap
对象中。
多次调用会产生很大的开销;你应该存储图像。
答案 1 :(得分:3)
每次需要使用来自Resources的图像时,要指出调用“ResourceManager.GetObject”还有另外一件事,它似乎每次都会创建一个新的Windows句柄。在你的情况下可能不是什么大不了的事,但如果你像我们一样坚持他们一段时间,可能会引起一个问题。
我们有一个DataGridView,我们将资源中的图像推送到网格的不同字段,当网格超过3000行时,我们实际上超过了32位程序允许的最大Windows句柄。
错误出现随机参数异常,消息“参数无效”。花了几个小时的时间才想到我们有内存泄漏,但最后发现我们用这个网格加载了这个GUI,应用程序处理的内容从700-1000到超过10K,甚至还没有完成加载,并且会导致整个程序无法恢复。所以我在这里建议选项2.
答案 2 :(得分:2)
我还在课程中实现了"read once then store in variable" concept。
举一个例子,这是我的代码的摘录:
internal static class MyResourcesHolder
{
private static Image _i1;
private static Image _i2;
private static Image _i3;
private static Image _i4;
private static Image _i5;
public static Image MyImage01 => _i1 ?? (_i1 = Resources.MyImage01);
public static Image MyImage02 => _i2 ?? (_i2 = Resources.MyImage02);
public static Image MyImage03 => _i3 ?? (_i3 = Resources.MyImage03);
public static Image MyImage04 => _i4 ?? (_i4 = Resources.MyImage04);
public static Image MyImage05 => _i5 ?? (_i5 = Resources.MyImage05);
}
也许有一天这会帮助某人。
答案 3 :(得分:1)
MSDN documentation表示ResourceManager.GetObject返回资源的值。由于听起来个别位图在运行时没有变化,因此我认为接近#2的唯一不足之处是你的内存占用量会更大。
答案 4 :(得分:0)
我有一个WinForms应用程序,它使用相同表单的许多实例,每个实例都有许多用于菜单和按钮的图像和图标等。所有这些图像都存储在自动生成的[ProjectName].Properties.Resources
类中。
我注意到内存使用量非常高;在仅仅10个左右的Form实例之后,它使用了数百MB的内存,并且在几个实例之后可以轻松地跨越1+ GB。我将问题追溯到ResourceManager.GetObject
方法。 GetObject
方法返回所请求的每个对象的新实例,这对我来说似乎不对。
为什么不将它们重用于将来的Form实例,而不是让所有这些图像实例仅仅为了超出范围而吸收内存?所以我创建了一个自定义的CachedResourceMananger
类,并覆盖了GetObject
方法,以返回所请求对象的缓存实例。
/// <summary>
/// A custom Resource Manager that provides cached instances of objects.
/// This differs from the stock ResourceManager class which always
/// deserializes and creates new instances of every object.
/// After the first time an object is requested, it will be cached
/// for all future requests.
/// </summary>
public class CachedResourceManager : System.Resources.ResourceManager
{
/// <summary>
/// A hashtable is used to store the objects.
/// </summary>
private Hashtable objectCache = new Hashtable();
public CachedResourceManager(Type resourceSource) : base(resourceSource)
{
}
public CachedResourceManager(string baseName, Assembly assembly) : base(baseName, assembly)
{
}
public CachedResourceManager(string baseName, Assembly assembly, Type usingResourceSet) : base(baseName, assembly, usingResourceSet)
{
}
public CachedResourceManager() : base()
{
}
/// <summary>
/// Returns a cached instance of the specified resource.
/// </summary>
public override object GetObject(string name)
{
return GetObject(name, null);
}
/// <summary>
/// Returns a cached instance of the specified resource.
/// </summary>
public override object GetObject(string name, CultureInfo culture)
{
// Try to get the specified object from the cache.
var obj = objectCache[name];
// If the object has not been cached, add it
// and return a cached instance.
if (obj == null)
{
objectCache[name] = base.GetObject(name, culture);
obj = objectCache[name];
}
return obj;
}
}
然后,我修改了自动生成的[ProjectName].Properties.Resources
类中的资源管理器属性和字段,以使用自定义资源管理器,将global::System.Resources.ResourceManager
替换为CachedResourceManager
。
internal class Resources
{
private static CachedResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static CachedResourceManager ResourceManager
{
get {
if (object.ReferenceEquals(resourceMan, null))
{
CachedResourceManager temp = new CachedResourceManager("Project.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
// Image/object properties for your resources
} // End of resources class
这大大减少了内存使用量,也极大地改善了新Form实例的加载时间。