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

Vaadin 8 Grid加载时内存溢出异常问题求助

Vaadin 8 Grid 内存溢出问题排查与解决

问题现象

  • 加载包含用户详情的Grid标签页时,应用因内存不足崩溃,2名以上用户同时访问时触发
  • 核心报错:
    Caused by: java.lang.OutOfMemoryError: GC overhead limit exceeded
    Caused by: org.postgresql.util.PSQLException: Ran out of memory retrieving query results.
    
  • 数据库查询速度快,但UI端加载缓慢

代码问题分析

  1. 全量数据加载:setDataSource(List<User> users)将所有用户数据一次性加载到内存,多用户会话同时持有全量数据时,内存占用急剧飙升。
  2. 详情组件重复创建:setDetailsGenerator中每次展开行详情都会新建UserDetailsView实例,大量重复实例持续占用内存。
  3. 转换器重复实例化:角色列渲染逻辑中,每次渲染都会新建UsersViewRoleConverter,增加不必要的对象创建与GC压力。
  4. 导出功能内存风险:Exporter.exportAsExcel(usersGrid)直接遍历Grid全量数据,导出时会瞬间占用大量内存。

解决方案

1. 实现分页懒加载(核心优化)

替换全量数据加载为DataProvider分页加载,每次仅获取当前页数据:

// 替换原有setDataSource方法
void setDataProvider(DataProvider<User, String> dataProvider) {
    usersGrid.setDataProvider(dataProvider);
}

后端配合分页查询(如Spring Data JPA的Pageable),每次返回20-50条数据,大幅降低单会话内存占用。

2. 优化详情组件创建

避免重复创建详情组件,可复用或延迟初始化:

private void createUsersGrid() {
    // ... 其他代码
    // 详情生成器可考虑轻量级实现,确保关闭时能被GC回收
    usersGrid.setDetailsGenerator(rowRef -> {
        UserDetailsView detailsView = new UserDetailsView(listener);
        if (rowRef != null) {
            detailsView.edit(rowRef);
        }
        return detailsView;
    });
}

3. 减少重复对象创建

将UsersViewRoleConverter实例化为类成员变量,避免每次渲染列都新建对象:

private final UsersViewRoleConverter roleConverter = new UsersViewRoleConverter();

// 角色列渲染逻辑
usersGrid.addColumn(user -> 
    roleConverter.convertToPresentation(user.getRoles(), new ValueContext())
).setCaption(COLUMN_ROLES);

4. 优化导出功能

导出全量数据时,单独执行分页查询拼接结果,避免一次性加载全量数据到内存:

Button export = new Button("Export");
export.setIcon(VaadinIcons.LIST_UL);
export.addStyleName("move-right");
StreamResource excelStreamResource = new StreamResource(() -> {
    // 后端分页获取全量用户数据
    List<User> allUsers = listener.getAllUsersForExport();
    // 指定导出字段,避免不必要的数据加载
    return Exporter.exportAsExcel(allUsers, User.class, 
        COLUMN_LAST_NAME, COLUMN_FIRST_NAME, COLUMN_USERNAME, COLUMN_EMAIL, COLUMN_ROLES, COLUMN_ENABLED);
}, "Users Report.xlsx");
FileDownloader excelFileDownloader = new FileDownloader(excelStreamResource);
excelFileDownloader.extend(export);

5. 数据库JDBC优化

调整PostgreSQL JDBC连接的fetchSize,避免一次性拉取所有查询结果到客户端内存:

// 在JDBC查询语句中设置fetch size
statement.setFetchSize(50);

6. 额外检查点

  • 检查User对象是否包含大字段(如Blob、Clob),若存在则延迟加载,仅在详情展开时获取
  • 用JProfiler等工具监控内存,确认是否存在未释放的Grid实例或User对象泄漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 19:05:18