maui-performance

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

.NET MAUI Performance Optimization

.NET MAUI 性能优化

Profiling

性能分析

  • dotnet-trace: Cross-platform profiler for all MAUI targets. Collect traces with:
    shell
    dotnet-trace collect --process-id <PID> --providers Microsoft-DotNETCore-SampleProfiler
  • PerfView (Windows only): Use for deep allocation and CPU analysis on WinUI targets.
  • Profile before optimizing — measure, don't guess.
  • dotnet-trace:适用于所有MAUI目标平台的跨平台性能分析器。使用以下命令收集跟踪数据:
    shell
    dotnet-trace collect --process-id <PID> --providers Microsoft-DotNETCore-SampleProfiler
  • PerfView(仅Windows):用于WinUI目标平台的深度内存分配和CPU分析。
  • 优化前先做性能分析——用数据说话,不要凭猜测。

Compiled Bindings

编译绑定

  • Always set
    x:DataType
    on pages/views to enable compiled bindings.
  • Compiled bindings are 8–20× faster than reflection-based bindings.
  • Required for NativeAOT and full trimming — reflection bindings break under trimming.
  • Apply
    x:DataType
    at the highest reasonable scope (page or root element).
xml
<ContentPage xmlns:vm="clr-namespace:MyApp.ViewModels"
             x:DataType="vm:MainViewModel">
    <Label Text="{Binding Title}" />
</ContentPage>
  • For
    DataTemplate
    inside
    CollectionView
    /
    ListView
    , set
    x:DataType
    on the template root:
xml
<DataTemplate x:DataType="model:Item">
    <Label Text="{Binding Name}" />
</DataTemplate>
  • Minimize unnecessary bindings: Static content that never changes doesn't need
    {Binding}
    . Use literal values or
    x:Static
    instead.
  • 始终在页面/视图上设置
    x:DataType
    以启用编译绑定。
  • 编译绑定的速度比基于反射的绑定快8-20倍
  • 这是NativeAOT和完全代码裁剪的必要条件——基于反射的绑定在裁剪后会失效。
  • 在尽可能高的作用域(页面或根元素)上应用
    x:DataType
xml
<ContentPage xmlns:vm="clr-namespace:MyApp.ViewModels"
             x:DataType="vm:MainViewModel">
    <Label Text="{Binding Title}" />
</ContentPage>
  • 对于
    CollectionView
    /
    ListView
    中的
    DataTemplate
    ,在模板根元素上设置
    x:DataType
xml
<DataTemplate x:DataType="model:Item">
    <Label Text="{Binding Name}" />
</DataTemplate>
  • 减少不必要的绑定:永远不会变化的静态内容不需要使用
    {Binding}
    ,改用字面量值或
    x:Static

Layout Optimization

布局优化

  • Avoid nested single-child layouts — a
    StackLayout
    with one child is pointless overhead.
  • Prefer
    Grid
    over nested
    StackLayout
    /
    VerticalStackLayout
    — Grid resolves layout in a single pass.
  • Use
    IsVisible="False"
    to hide elements rather than adding/removing from the tree at runtime.
  • Remove unnecessary wrapper containers — every layout adds a measure/arrange pass.
  • Avoid
    AbsoluteLayout
    when
    Grid
    with row/column definitions achieves the same result.
  • Set explicit
    WidthRequest
    /
    HeightRequest
    where sizes are known to reduce measure passes.
  • 避免嵌套单元素布局——仅包含一个子元素的
    StackLayout
    会造成无意义的性能开销。
  • 优先使用
    Grid
    而非嵌套的
    StackLayout
    /
    VerticalStackLayout
    ——Grid只需一次遍历即可完成布局计算。
  • 使用
    IsVisible="False"
    隐藏元素,而非在运行时从布局树中添加/移除元素。
  • 移除不必要的包装容器——每个布局都会增加一次测量/排列的开销。
  • 当使用带行列定义的
    Grid
    可以实现相同效果时,避免使用
    AbsoluteLayout
  • 在已知尺寸的元素上设置明确的
    WidthRequest
    /
    HeightRequest
    ,以减少测量次数。

CollectionView and ListView

CollectionView 与 ListView

  • Use
    ItemSizingStrategy="MeasureFirstItem"
    on
    CollectionView
    when items have uniform height — avoids measuring every item individually.
xml
<CollectionView ItemSizingStrategy="MeasureFirstItem"
                ItemsSource="{Binding Items}">
  • Prefer
    CollectionView
    over
    ListView
    for new development.
  • Keep
    DataTemplate
    visual trees shallow — fewer nested layouts per item.
  • CollectionView
    中的项具有统一高度时,设置
    ItemSizingStrategy="MeasureFirstItem"
    ——避免逐个测量每个项。
xml
<CollectionView ItemSizingStrategy="MeasureFirstItem"
                ItemsSource="{Binding Items}">
  • 新开发优先使用
    CollectionView
    而非
    ListView
  • 保持
    DataTemplate
    的视觉树层级简洁——每个项的嵌套布局越少越好。

Image Optimization

图片优化

  • Size images to display resolution — don't load a 4000×3000 image for a 200×200 display.
  • Use
    Aspect="AspectFill"
    or
    AspectFit
    and set explicit dimensions.
  • Cache downloaded images:
    CachingEnabled="True"
    (default) on
    UriImageSource
    , set
    CacheValidity
    .
  • Use platform-appropriate formats (WebP for Android, HEIF/PNG for iOS).
  • For icons and simple graphics, prefer SVG or vector-based font icons.
  • 根据显示分辨率调整图片尺寸——不要为200×200的显示区域加载4000×3000的图片。
  • 使用
    Aspect="AspectFill"
    AspectFit
    并设置明确的尺寸。
  • 缓存下载的图片
    UriImageSource
    默认启用
    CachingEnabled="True"
    ,可设置
    CacheValidity
  • 使用平台适配的格式(Android用WebP,iOS用HEIF/PNG)。
  • 对于图标和简单图形,优先使用SVG或基于矢量的字体图标。

Resource Dictionaries

资源字典

  • App-level (
    App.xaml
    ): Shared styles, colors, converters used across multiple pages.
  • Page-level: Styles/resources specific to a single page — keeps App.xaml lean.
  • Avoid duplicating resources across dictionaries.
  • Use
    MergedDictionaries
    to organize large resource sets without bloating a single file.
  • 应用级
    App.xaml
    ):存放多页面共享的样式、颜色、转换器。
  • 页面级:存放仅单个页面使用的样式/资源——保持App.xaml简洁。
  • 避免在多个字典中重复定义资源。
  • 使用
    MergedDictionaries
    组织大型资源集合,避免单个文件过于臃肿。

Startup Optimization

启动优化

  • Minimize work in
    App
    constructor and
    MainPage
    constructor.
  • Defer non-essential service registration — use lazy initialization where possible.
  • Reduce the number of XAML pages parsed at startup (use
    Shell
    routing for deferred loading).
  • Remove unused
    Handlers
    /
    Effects
    registrations from
    MauiProgram.cs
    .
  • On Android, ensure
    AndroidManifest.xml
    doesn't force unnecessary permissions checks at launch.
  • 减少
    App
    构造函数和
    MainPage
    构造函数中的操作。
  • 延迟非必要的服务注册——尽可能使用延迟初始化。
  • 减少启动时解析的XAML页面数量(使用
    Shell
    路由实现延迟加载)。
  • MauiProgram.cs
    中移除未使用的
    Handlers
    /
    Effects
    注册。
  • 在Android上,确保
    AndroidManifest.xml
    不会在启动时强制进行不必要的权限检查。

Trimming

代码裁剪

Enable IL trimming to reduce app size and remove unused code:
xml
<PropertyGroup>
    <PublishTrimmed>true</PublishTrimmed>
    <TrimMode>full</TrimMode>
</PropertyGroup>
  • Test thoroughly — trimming can remove code accessed only via reflection.
  • Use
    [DynamicDependency]
    or
    [UnconditionalSuppressMessage]
    to preserve reflection targets.
  • Compiled bindings are essential — reflection-based bindings will be trimmed away.
启用IL裁剪以减小应用体积并移除未使用的代码:
xml
<PropertyGroup>
    <PublishTrimmed>true</PublishTrimmed>
    <TrimMode>full</TrimMode>
</PropertyGroup>
  • 彻底测试——裁剪可能会移除仅通过反射访问的代码。
  • 使用
    [DynamicDependency]
    [UnconditionalSuppressMessage]
    保留反射目标。
  • 编译绑定是必要条件——基于反射的绑定会被裁剪掉。

NativeAOT

NativeAOT

  • NativeAOT compiles to native code ahead-of-time for faster startup and smaller footprint.
  • Requirements: compiled bindings, no unconstrained reflection, trimming-compatible code.
xml
<PropertyGroup>
    <PublishAot>true</PublishAot>
    <PublishTrimmed>true</PublishTrimmed>
</PropertyGroup>
  • Audit third-party NuGet packages for trimming/AOT compatibility.
  • Use
    [JsonSerializable]
    source generators instead of reflection-based JSON serialization.
  • Run
    dotnet publish
    with AOT to verify no warnings before shipping.
  • NativeAOT提前编译为原生代码,实现更快的启动速度和更小的内存占用。
  • 要求:使用编译绑定、无无约束反射、代码兼容裁剪。
xml
<PropertyGroup>
    <PublishAot>true</PublishAot>
    <PublishTrimmed>true</PublishTrimmed>
</PropertyGroup>
  • 检查第三方NuGet包是否兼容裁剪/AOT。
  • 使用
    [JsonSerializable]
    源生成器替代基于反射的JSON序列化。
  • 发布前使用
    dotnet publish
    命令结合AOT进行验证,确保无警告。

Quick Checklist

快速检查清单

  1. x:DataType
    on all pages, templates, and data-bound views
  2. ✅ No nested single-child layouts
  3. ✅ Grid preferred over nested StackLayouts
  4. ✅ Images sized to display, caching enabled
  5. ItemSizingStrategy="MeasureFirstItem"
    on uniform CollectionViews
  6. ✅ Startup work minimized and deferred
  7. ✅ Trimming enabled and tested
  8. ✅ Profile with dotnet-trace before and after changes
  1. ✅ 所有页面、模板和数据绑定视图都已设置
    x:DataType
  2. ✅ 无嵌套单元素布局
  3. ✅ 优先使用Grid而非嵌套StackLayout
  4. ✅ 图片已按显示尺寸调整,缓存已启用
  5. ✅ 统一高度的CollectionView已设置
    ItemSizingStrategy="MeasureFirstItem"
  6. ✅ 启动时的操作已最小化并延迟执行
  7. ✅ 已启用代码裁剪并完成测试
  8. ✅ 优化前后均使用dotnet-trace进行性能分析