从外置SQL Server读取学生列表触发OutOfMemoryError的实现方案
移动端直连SQL Server读取学生档案触发内存溢出问题
正在开发用于展示学生列表及个人档案的移动端应用,为实现数据脱离手机本地存储,计划采用SQL Server作为外部数据存储端。在从SQL Server数据表查询读取数据的过程中,程序抛出java.lang.OutOfMemoryError内存溢出错误,无法顺畅完成数据读取流程,需要匹配正确的实现思路与优化方案。
现有实现代码
ArrayList<Student> students = new ArrayList(); if (connection!=null){ Statement statement = null; try { statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery("Select * from STUDENT_TABLE;"); while (resultSet.next()){ //column 1 - last name, column 2 - name, column 3 - class students.add(new Student(resultSet.getString(1), resultSet.getString(1), resultSet.getString(1))); } } catch (SQLException e) { e.printStackTrace(); } } else { text.setText(R.string.connection_is_null); }
核心问题定位
- 全量加载逻辑缺陷:执行
Select * from STUDENT_TABLE无任何数据量限制,一旦学生表数据规模超出移动端应用可承载的堆内存阈值,就会在逐行向ArrayList写入数据的过程中触发内存溢出。移动端应用的可用堆内存额度远低于PC端,即使是几十万条纯字符串数据,也可能占满所有可用内存。 - JDBC驱动默认缓存问题:SQL Server JDBC驱动默认会把查询到的全量结果一次性加载到客户端内存做缓存,而非逐行从服务端拉取数据,相当于查询结果在驱动层缓存一份、手动存入ArrayList再存一份,双重内存占用进一步推高了OOM的触发概率。
- 代码逻辑错误:循环构造Student对象时,三个入参全部读取第1列的值
resultSet.getString(1),和注释标注的“列1为姓氏、列2为名字、列3为班级”的列规则完全不匹配,即使没有触发OOM,最终加载的学生数据也存在错误。
实现思路与优化方案
1. 架构层面风险规避
首先要明确:移动端App长期直连公网SQL Server本身是高风险、低效率的实现方案——一方面直连没有权限隔离,很容易把数据库账号暴露在客户端代码里带来安全隐患;另一方面移动端网络不稳定,长连接的维持成本远高于通过中间层接口交互。当前阶段若处于调试期需要直连,可先落地以下优化解决内存溢出问题。
2. 分页查询替代全量加载
- 不再一次性拉取全表数据,按需通过游标分页的方式拉取数据:每次只查询当前列表需要展示的10-20条数据,用户滑动到列表底部时再触发下一页查询,从根源上减少单次加载的数据量。
- 替换
Select *的查询写法,只拉取业务必须的展示字段,避免读取存储二进制档案的大字段,降低单条数据的内存占用。
3. 调整JDBC结果集拉取模式
创建Statement时调整配置,让驱动逐行从服务端拉取数据,避免全量结果在客户端内存缓存:
statement = connection.createStatement( ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY ); // 设置单次从服务端拉取的行数阈值,避免全量缓存 statement.setFetchSize(100);
4. 修正业务逻辑错误
构造Student对象时严格匹配列索引取值,修正全量读第1列的bug:
while (resultSet.next()){ // 列1-姓氏,列2-名字,列3-班级 students.add(new Student( resultSet.getString(1), resultSet.getString(2), resultSet.getString(3) )); }
5. 内存回收优化
在页面退出、列表数据不再需要时,及时清空持有Student列表的引用,让垃圾回收机制可以回收不再使用的对象;避免在静态变量中长期持有大列表对象,减少内存的不必要常驻占用。
内容的提问来源于stack exchange,提问作者J El
相关产品推荐
相关产品推荐

