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
排查方向与解决思路
优化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); } }使用DTO减少传输数据体积
检查VirtualDataModel_STG_Ind等实体类是否包含冗余字段或导航属性,创建仅保留前端所需字段的DTO类,服务端返回DTO而非原始实体,降低序列化后的数据量。优化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();排查客户端内存泄漏
使用浏览器DevTools的Memory面板拍摄内存快照,对比数据加载前后的内存变化,检查是否存在未释放的组件引用、事件订阅或循环引用导致GC无法回收内存。调整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>简化内存中的数据处理逻辑
移除循环中重复的排序操作(服务端已完成排序),减少不必要的内存分配: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
相关产品推荐
相关产品推荐

