C# 静态类成员和 System.Windows.Controls.Image 性能问题
我目前正在调查应用程序中的性能问题,并强调了以下内容;
我有一个类 -
public static class CommonIcons
{
...
public static readonly System.Windows.Media.ImageSource Attributes = typeof(CommonIcons).Assembly.GetImageFromResourcePath("Resources/attributes.png");
...
}
作为测试工具,我有以下代码使用该类来显示问题 -
for (int loop = 0; loop < 20000; loop++)
{
// store time before call
System.Windows.Controls.Image image = new System.Windows.Controls.Image
{
Source = CommonIcons.Attributes,
Width = 16,
Height = 16,
VerticalAlignment = VerticalAlignment.Center,
SnapsToDevicePixels = true
};
// store time after call
// log time between before and after
}
在循环开始时,时间差小于 0.001 秒,但在 20000 之后,时间差增加到 0.015 秒。
如果我不使用静态成员并直接引用我的图标,那么我不会受到性能影响,即
for (int loop = 0; loop < 20000; loop++)
{
// store time before call
System.Windows.Controls.Image image = new System.Windows.Controls.Image
{
Source = typeof(CommonIcons).Assembly.GetImageFromResourcePath("Resources/attributes.png"),
Width = 16,
Height = 16,
VerticalAlignment = VerticalAlignment.Center,
SnapsToDevicePixels = true
};
// store time after call
// log time between before and after
}
但在我的现实世界程序中,我不想在每次调用时创建图像源(增加内存,直到垃圾收集),这就是为什么使用静态成员。然而,我也无法忍受性能下降。
有人可以解释为什么原始代码会造成这种性能损失吗?对于我想做的事情还有更好的解决方案吗?
谢谢
I am currently investigating a performance issue in an application and have highlighted the following;
I have a class -
public static class CommonIcons
{
...
public static readonly System.Windows.Media.ImageSource Attributes = typeof(CommonIcons).Assembly.GetImageFromResourcePath("Resources/attributes.png");
...
}
As a test harness I then have the following code using this class to show the issue -
for (int loop = 0; loop < 20000; loop++)
{
// store time before call
System.Windows.Controls.Image image = new System.Windows.Controls.Image
{
Source = CommonIcons.Attributes,
Width = 16,
Height = 16,
VerticalAlignment = VerticalAlignment.Center,
SnapsToDevicePixels = true
};
// store time after call
// log time between before and after
}
At the start of the loop the time difference is less than 0.001 seconds, but after 20000 goes this has increased to 0.015 seconds.
If I don't use the static member and directly refer to my icon, then I do not have the performance hit, i.e.
for (int loop = 0; loop < 20000; loop++)
{
// store time before call
System.Windows.Controls.Image image = new System.Windows.Controls.Image
{
Source = typeof(CommonIcons).Assembly.GetImageFromResourcePath("Resources/attributes.png"),
Width = 16,
Height = 16,
VerticalAlignment = VerticalAlignment.Center,
SnapsToDevicePixels = true
};
// store time after call
// log time between before and after
}
But in my real world program I don't want to be creating the imagesource on every call (increased memory until a garbage collection), hence why a static member is used. However I also cannot live with the performance hit.
Can someone explain why the original code is creating this performance hit? And also a better solution for what I am trying to do?
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
闻起来像是与垃圾收集有关。我想知道
ImageSource
和Image
之间是否存在某种耦合,这会导致第一种情况出现问题。您是否查看过每种情况下测试工具的内存使用情况?出于兴趣,如果在每次迭代结束时将
Source
设置为 null 会发生什么?我知道这有点愚蠢,但这是它作为测试工具的自然推论:)这可能进一步表明它是源和图像之间的链接......It smells like something to do with garbage collection. I wonder whether there's some kind of coupling between the
ImageSource
and theImage
which is causing problems in your first case. Have you looked to see what the memory usage of your test harness looks like in each case?Out of interest, what happens if you set the
Source
to null at the end of each iteration? I know this is a bit silly, but then that's a natural corollary of it being a test harness :) It might be a further indication that it's a link between the source and the image...您可以在 CommonIcons 类中仅存储像“Resources/attributes.png”这样的常量字符串吗?
Can you store only constant strings like "Resources/attributes.png" in your CommonIcons class ?
区别不在于静态成员与否,而是在第一个版本中,您创建了 20000 个图像,所有图像都具有相同的图像源。我不知道到底发生了什么,但在幕后可能会自动创建代表来处理 imagesource 和 image 之间的通信,并且每次 imagesource 中发生事件时,都需要通知 20000 个客户端,所以这是一个很大的任务性能受到打击。
在第二个版本中,创建的 20000 个图像中的每一个都有其自己的图像源,因此您不会遇到这种开销。
注意,在使用完图像等图形对象后,您应该始终使用它们的
Dispose()
方法来处理它们,这会稍微加快您的应用程序的速度并降低您的总体性能内存使用情况。The difference is not between static member or not, but it is that in the first version you create 20000 images all having the same imagesource. I don't know exactly what is going on, but under the hood there may be delegates created automatically which handle communication between imagesource and image and everytime if an event in the imagesource occurs, 20000 clients needs to be notified, so this is a large performance hit.
In the second version, each of the 20000 created images have their own imagesource so you don't experience this overhead.
Note that you should always dispose graphical objects like Images with their
Dispose()
-method after you are done with them, this will speed up your application a bit and lowers your general memory usage.