java—如果程序返回大量记录,如何解决内存不足的问题

iovurdzv  于 2021-07-13  发布在  Java
关注(0)|答案(3)|浏览(315)

我目前正在开发一个java应用程序。使用的数据库是sybase ase 15.0。目前,我在其中一个场景中遇到以下错误: java.lang.OutOfMemoryError: Java heap space 我的代码中有以下过程调用:

CallableStatement cStmt = null;
ResultSet rs = null;
ArrayList list = new ArrayList();
Connection con = getConnection();
cStmt = con.prepareCall("call <proc-name>(?,?)", ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
boolean b;
// .....
// .....
while(rs.next()){
  List dList = new ArrayList();
  T t = new T();
  t.setProp1(rs.getBoolean("isAvailable"));
  t.setProp2(rs.getString("Name"));
  t.setDList(dList);
  ....
  ....
  t.setPropN(rs.getString("Property-name"));//many properties are read
  //  from db and POJO is populated.

  b = true;
  int Id = rs.getInt("Id");

  do{
     D d = new D();
     d.setProp1(rs.getFloat("<property-name"));
     ....
     ....
     d.setPropN(rs.getString("Property-name"));//many properties are read      
     dList.add(d);

     if(rs.next()){

         if(rs.getInt("Id")!=Id){
              b = false;
              rs.previous();    
         }

     } else {
             b = false;
             rs.previous();
     }
  } while (b);

  list.add(t);
}

过程接收日期范围作为其参数。如果日期范围较大,则返回大量记录。对于少量记录,它可以正常工作,但对于大型记录,它会出现“内存不足”异常。我观察到,如果记录数大于11997,则会产生此错误。
我读过简单的resultset在堆内存中存储记录,但它应该和可滚动的resultset一起工作,对吗?
在这种情况下,如何删除此异常。

omqzjyyz

omqzjyyz1#

首先只是一个资源:使用 try (ResultSet rs = cStmt.query()) { ... } 之后关闭结果集。
将存储过程的结果存储在一个(临时)表中,并使用select和paged。然后结果集可以迭代。调用可能会将所有数据传递给jdbc。我不知道sybase的存储过程功能,但也许你可以在那里做一些事情。
检查,使用varchar而不是char之类的。
使用utf-8而不是utf-16le。
在java中存储时,可以在标识Map中缓存相等的字符串/大小数,以便在数据中只使用第一个对象示例。

mfuanj7w

mfuanj7w2#

为什么不使用限制?如果你不能限制可能产生一个巨大数据集的日期范围,你应该使用限制,即你用前100个,然后用下100个等等做一些事情,那么你在内存中只有当前的100个。

wlwcrazw

wlwcrazw3#

不如简单地增加虚拟机的默认最大堆内存?

-Xmx<size> - to set the maximum Java heap size
-Xms<size> - to set the initial Java heap size

您还可以尝试使用探查器更精确地查明内存泄漏。你必须小心while循环,你在里面放了什么,什么是适合gc的。
查看这篇关于对象创建成本的信息性文章:
http://drmirror.net/2013/06/06/object-creation/
java的高效内存实践:https://www.cs.virginia.edu/kim/publicity/pldi09tutorials/memory-efficient-java-tutorial.pdf
更新:针对“有没有其他方法使结果集不能同时将所有记录读入内存并以块的形式读取它们?”尝试在resultset(rs)上使用setfetchsize
了解有关setfetch大小的更多信息:
https://stackoverflow.com/a/858863/4807777
https://stackoverflow.com/a/20900045/4807777
https://stackoverflow.com/a/26235298/4807777
更新2以响应循环代码:
在循环外声明所有变量,并根据需要初始化它们;所以在循环之前:

List dList;
T t;
int Id
D d;
while(rs.next()){
  dList = new ArrayList();
  t = new T();
  // and so on...

  list.add(t);
}

然后再试一次。

相关问题