You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Microsoft Blazor客户端Razor组件出现OutOfMemory异常求助

Blazor客户端Razor组件突发OutOfMemory异常排查求助

我有一个包含约30个视图、控制器、接口和服务的Microsoft Blazor应用,近期客户端Razor组件突发**"OutOfMemory"**异常,已开展排查:服务计算后返回11个对象,控制器正常响应该列表,但Razor组件抛出异常。

服务层代码

public List<VirtualDataModel_STG_Ind> GetDataModel_STGs(int datamodel_id, bool isselectedobject)
{
    try
    {
        List<VirtualDataModel_STG_Ind> datamodel_stgs = new();
        DataModel? dataModel = _dbContext.DataModels.Where(x => x.datamodel_id == datamodel_id).FirstOrDefault();
        if (dataModel != null)
        {
            //dataModel = DataSecurity.ObjectFilter(dataModel, "view", _dbContext, _httpContextAccessor);

            //PROVISION TWO LISTS AND THEN FOREACH TO HANDLE PERFORMANCE
            List<DataModel_STG_Table_Ind> datamodel_stg_tables_ind = _dbContext.DataModel_STG_Tables_Ind
                .Where(x => x.datamodel_id == datamodel_id)
                .OrderBy(x => x.datamodel_stg_table_schm)
                .ThenBy(x => x.datamodel_stg_table_name)
                .ToList();
            List<DataModel_STG_Field_Ind> datamodel_stg_fields_inds = _dbContext.DataModel_STG_Fields_Ind
                .Where(x => x.datamodel_id == datamodel_id)
                .OrderBy(x => x.datamodel_stg_table_schm)
                .ThenBy(x => x.datamodel_stg_table_name)
                .ThenBy(x => x.datamodel_stg_field_name)
                .ToList();

            //IF SENSITIVEOBJECT
            if (isselectedobject)
            {
                datamodel_stg_fields_inds = datamodel_stg_fields_inds.Where(x => x.datamodel_stg_field_is_selected == true).ToList();
            }

            foreach (DataModel_STG_Table_Ind datamodel_stg_table_ind in datamodel_stg_tables_ind)
            {
                if (datamodel_stg_table_ind != null)
                {
                    List<DataModel_STG_Field_Ind> datamodel_stg_fields_ind = datamodel_stg_fields_inds
                        .Where(x => x.datamodel_id == datamodel_stg_table_ind.datamodel_id && x.datamodel_stg_table_schm == datamodel_stg_table_ind.datamodel_stg_table_schm && x.datamodel_stg_table_name == datamodel_stg_table_ind.datamodel_stg_table_name)
                        .OrderBy(x => x.datamodel_stg_table_schm)
                        .ThenBy(x => x.datamodel_stg_table_name)
                        .ThenBy(x => x.datamodel_stg_field_name).ToList();

                    if (datamodel_stg_fields_ind != null)
                    {
                        if (datamodel_stg_fields_ind.Count() > 0)
                        {
                            VirtualDataModel_STG_Ind virtualdatamodel_stg_ind = new()
                            {
                                datamodel_stg_table = datamodel_stg_table_ind,
                                datamodel_stg_table_fields = datamodel_stg_fields_ind,
                            };
                            datamodel_stgs.Add(virtualdatamodel_stg_ind);
                        }
                    }
                }
            }
        }
        return datamodel_stgs;
    }
    catch
    {
        throw;
    }
}

控制器代码

[HttpGet, Route("/api/datamodel/view/{datamodel_id:int}/stg/view/{isselectedobject:bool}")]
public async Task<List<VirtualDataModel_STG_Ind>> GetDataModel_STGs(int datamodel_id, bool isselectedobject)
{
    try {
        List<VirtualDataModel_STG_Ind> obj = await Task.FromResult(_IDataModel.GetDataModel_STGs(datamodel_id, isselectedobject));
        return obj;
    }
    catch { throw; }
}

Razor组件代码

protected async Task GetDataModel_STG(int datamodel_id)
{
    try
    {
        Loading_Start();
        datamodel_stgList = await Http.GetFromJsonAsync<List<VirtualDataModel_STG_Ind>>("/api/datamodel/view/" + datamodel_id + "/stg/view/" + isSelectedObject );
                    Loading_Stop();
    }
    catch (Exception e)
    {
        await ShowTheExceptionModal(e.Message);
    }
}

已尝试的操作

  • 移除Razor组件中所有用于主从表形式展示datamodel_stgList的代码
  • 在Visual Studio中监测响应期间内存占用,约为200-250MB
  • 将项目从.NET 6升级至.NET 7

排查方向与解决思路

  1. 优化JSON反序列化的内存使用
    替换GetFromJsonAsync为流式反序列化,减少内存峰值:

    protected async Task GetDataModel_STG(int datamodel_id)
    {
        try
        {
            Loading_Start();
            using var response = await Http.GetStreamAsync($"/api/datamodel/view/{datamodel_id}/stg/view/{isSelectedObject}");
            datamodel_stgList = await JsonSerializer.DeserializeAsync<List<VirtualDataModel_STG_Ind>>(response, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
            Loading_Stop();
        }
        catch (Exception e)
        {
            await ShowTheExceptionModal(e.Message);
        }
    }
    
  2. 使用DTO减少传输数据体积
    检查VirtualDataModel_STG_Ind等实体类是否包含冗余字段或导航属性,创建仅保留前端所需字段的DTO类,服务端返回DTO而非原始实体,降低序列化后的数据量。

  3. 优化EF Core查询的内存占用
    在EF查询中添加.AsNoTracking()避免实体缓存,同时将isselectedobject过滤条件直接嵌入查询,减少内存中处理的数据量:

    List<DataModel_STG_Field_Ind> datamodel_stg_fields_inds = _dbContext.DataModel_STG_Fields_Ind
        .AsNoTracking()
        .Where(x => x.datamodel_id == datamodel_id && (!isselectedobject || x.datamodel_stg_field_is_selected == true))
        .OrderBy(x => x.datamodel_stg_table_schm)
        .ThenBy(x => x.datamodel_stg_table_name)
        .ThenBy(x => x.datamodel_stg_field_name)
        .ToList();
    
  4. 排查客户端内存泄漏
    使用浏览器DevTools的Memory面板拍摄内存快照,对比数据加载前后的内存变化,检查是否存在未释放的组件引用、事件订阅或循环引用导致GC无法回收内存。

  5. 调整Blazor WebAssembly内存限制
    若为WASM应用,在wwwroot/index.html中调整内存上限:

    <script src="_framework/blazor.webassembly.js" autostart="false"></script>
    <script>
      Blazor.start({
        loadBootResource: function (type, name, defaultUri, integrity) {
          if (type === 'dotnetjs') {
            return defaultUri + '?max-old-space-size=512';
          }
          return defaultUri;
        }
      });
    </script>
    
  6. 简化内存中的数据处理逻辑
    移除循环中重复的排序操作(服务端已完成排序),减少不必要的内存分配:

    List<DataModel_STG_Field_Ind> datamodel_stg_fields_ind = datamodel_stg_fields_inds
        .Where(x => x.datamodel_stg_table_schm == datamodel_stg_table_ind.datamodel_stg_table_schm && x.datamodel_stg_table_name == datamodel_stg_table_ind.datamodel_stg_table_name)
        .ToList();
    

内容的提问来源于stack exchange,提问作者Stavros Koureas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 00:27:02