wpfitemscontrolimage内存占用

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了wpfitemscontrolimage内存占用相关的知识,希望对你有一定的参考价值。

WPF中渲染层有三层:

Rendering Tier 0 :没有图形硬件加速度。所有图形功能都使用软件加速度。directx 版本级别小于版本 9.0
Rendering Tier 1 :某些图形功能使用图形硬件加速度。directx 版本级别大于或等于版本 9.0
Rendering Tier 2 :大多数图形功能使用图形硬件加速度。directx 版本级别大于或等于版本 9.0
RenderCapability.Tier属性可以在运行时检索渲染层,以动态决定部分渲染逻辑

布局
布局是一个数学密集型过程,布局系统将为集合中的每个子成员完成两次传递:测量传递、排列传递。
每个子对象都提供了自己的 Measure 和Arrange 方法的重写实现,以提供自己特定的布局行为。
最简单的说,布局是一个递归系统,它导致元素在屏幕上被调整大小、定位和绘制。
子 UIElement 对象首先测量其核心属性,从而开始布局过程。评估对象的与大小相关的 FrameworkElement 属性,例如 Width、Height 和 Margin。
应用特定于面板的逻辑,例如 DockPanel 的 Dock 属性或 StackPanel 的 Orientation 属性。
在测量完所有子对象后,将排列或定位内容。子对象的集合被绘制到屏幕上。
如果发生以下任何操作,将再次调用布局传递过程:

一个子对象被添加到集合中。
LayoutTransform 应用于子对象。
为子对象调用 UpdateLayout 方法。
当使用影响度量或排列传递的元数据标记的依赖属性的值发生更改时。
尽可能使用Canvas等简单布局,少使用grid、stackpanel
创建视觉树或逻辑树时遵循Top-Down原则
性能对照
Action

Tree building (in ms)

Render—includes tree building (in ms)

Bottom-up

366

454

Top-down

11

96

Top-Down示例

private void OnBuildTreeTopDown(object sender, RoutedEventArgs e)

TextBlock textBlock = new TextBlock();
textBlock.Text = "Default";

DockPanel parentPanel = new DockPanel();
DockPanel childPanel;

myCanvas.Children.Add(parentPanel);
myCanvas.Children.Add(textBlock);

for (int i = 0; i < 150; i++)

textBlock = new TextBlock();
textBlock.Text = "Default";
parentPanel.Children.Add(textBlock);

childPanel = new DockPanel();
parentPanel.Children.Add(childPanel);
parentPanel = childPanel;


1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
使用Drawing而不是Sharp
Shape 派生自 FrameworkElement,使用将会显著增加内存消耗,建议考虑使用轻量级的 Drawing

图像
默认情况下,WPF 会加载图像并将其解码为全尺寸。若只需要缩略图,可以通过设置图像模式为低质量模式

RenderOptions.SetBitmapScalingMode(MyImage, BitmapScalingMode.LowQuality);
1.
考虑使用低质量模式
始终将图像解码为所需的大小
将图像组合成单个图像
其他注意点
释放对象之前必须删除委托
定义资源然后共享引用,而不是在XAML中定义内联引用
尽可能使用静态资源
使用Run而不是Textblock !!!如果使用run来显示文本,则需要注意尽量不要对run设置属性,而是设置在textblock上!!!
<!-- Run is used to set text properties. -->
<TextBlock>
<Run FontWeight="Bold">Hello, world</Run>
</TextBlock>

<!-- TextBlock is used to set text properties, which is more efficient. -->
<TextBlock FontWeight="Bold">
Hello, world
</TextBlock>
1.
2.
3.
4.
5.
6.
7.
8.
9.
文本块类型

创建时间(ms)

渲染时间(ms)

设置文本属性

146

540

设置文本属性

43

453

文本频繁更新时避免数据绑定到Label.Content属性而是使用Textblock.Text
数据绑定属性

更新时间(ms)

Label.Content

835

Textblock.Text

242

避免直接绑定IList而是使用ObservableCollection
绑定ItemsControl时使用IList而不是IEnumerable,使用IEnumerable将创建包装器IList 对象
虚拟化
使用列表型控件如ListView、ComboBox时如果列表数据较多,则应该考虑使用虚拟化。
上文中提及到子元素将需要计算布局大小和位置,通常这些元素并不是一次性显示在页面上,所以延迟计算是有意义的,
使用虚拟化即可实现延迟这些计算,数据虚拟化仅将屏幕上可见的数据项存储在内存中。

默认情况下,当 ListView 和 ListBox 控件的列表项绑定到数据时,会为它们启用 UI 虚拟化。
可以通过将 VirtualizingStackPanel.IsVirtualizing 附加属性设置为True来启用 TreeView 虚拟化。
如果要为派生自 ItemsControl 的自定义控件或使用 StackPanel 类的现有项目控件(例如 ComboBox)启用 UI 虚拟化,
可以将 ItemsPanel 设置为 VirtualizingStackPanel 并将 IsVirtualizing 设置为True。

如果应用程序将 ListBoxItem 对象显式添加到 ListBox,则 ListBox 不会虚拟化 ListBoxItem 对象。

容器回收
填充使用 UI 虚拟化的 ItemsControl 时,它会为滚动到视图中的每个项目创建一个项目容器,并为每个滚动出视图的项目销毁该项目容器。
容器回收使控件能够为不同的数据项重用现有的项容器,以便在用户滚动 ItemsControl 时不会不断地创建和销毁项容器。
您可以通过将 VirtualizationMode 附加属性设置为 Recycling 来选择启用项目回收。任何支持虚拟化的 ItemsControl 都可以使用容器回收。
VirtualizingStackPanel 在一个方向(水平或垂直)提供对 UI 虚拟化的内置支持。如果要对控件使用双向虚拟化,
则必须实现扩展 VirtualizingStackPanel 类的自定义面板。 VirtualizingStackPanel 类公开了诸如
OnViewportSizeChanged、LineUp、PageUp 和 MouseWheelUp 之类的虚拟方法。这些虚拟方法使您能够检测列表可见部分的更改并相应地处理它。

默认情况下,当用户在滚动条上拖动拇指时,内容视图会不断更新。如果控件中的滚动速度较慢,请考虑使用延迟滚动。在延迟滚动中,内容仅在用户松开拇指时更新。
要实现延迟滚动,请将 IsDeferredScrollingEnabled 属性设置为true。 IsDeferredScrollingEnabled 是一个附加属性,可以在 ScrollViewer 和任何在其控件模板中具有 ScrollViewer 的控件上设置。
参考技术A 核心代码:

private BitmapImage ReadImageFiletToBinary(string fileName)

using (var stream = new FileStream(fileName, FileMode.Open))

var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;

int streamLen = (int)stream.Length;
byte[] imageData = new byte[stream.Length];
stream.Read(imageData, 0, streamLen);

bitmapImage.StreamSource = new MemoryStream(imageData, 0, streamLen);

bitmapImage.DecodePixelWidth = 200; //设置解码后图像的宽度,图像变小,解析变快
bitmapImage.EndInit();
return bitmapImage;



这样占用的内存很低,原本直接读取10几张图需要占用150M内存,现在只需不到5M
参考技术B 最近开发一个WPF(4.0)桌面程序,运行起来就占500MB内存,页面切换有点卡,鼠标移动到按钮上的悬停效果也有点卡,界面也不是很复杂(要是用winform的话顶多占100MB),用过的控件也就是单选/itemscontrol/grid/stackpanel/textblock/image/blureffect/button,自己就定义了一个按钮样式,样式结构也不复杂,但我不清楚为什么就占那么大内存,以至于程序有点卡顿,

以上是关于wpfitemscontrolimage内存占用的主要内容,如果未能解决你的问题,请参考以下文章

使用gawk记录一段时间内,某个进程占用内存和CPU的情况

docker-index.exe内存占用大

C++程序,内存占用一直增加,最后无法分配内存而中断

C++中一个class类对象占用多少内字节(7个例子,很清楚)

cgroup 内存泄露问题排查记录

服务器内存占用过高如何解决?