内存溢出问题

刘德龙 2014-04-14 04:36:30
目前在写一个程序,从远程数据库读取数据,然后插入本机数据库。
由于之后远程数据库和本机数据库将不是同一种数据库,现在的处理方法是先select * from 读取远程数据库的数据,再经过代码处理后插入到本机数据库。 但是数据量一大(例如当前程序读取的数据有30万条记录),就会出报内存溢出错误。
想问各位大侠们,如何在代码里加上正确的释放内存的方法?
曾经也曾加上过System.gc()方法,但是经事实和网上解析,gc方法也不是马上释放内存的,没用。

public static void downLoadFiber(Context context,String domain,String region)throws SQLException
{
logger.info("开始下载纤芯数据...");
Connection conn_remote=context.getConnection1();//本链接为访问远程数据库
Connection conn_local=context.getConnection();//本链接为访问本地数据库
long a0 = System.currentTimeMillis () ;
PreparedStatement stmt = null ;
String delSql = "DELETE FROM GISFIBER FB WHERE FB.ID IN (SELECT DISTINCT F.ID FROM GISCABLESECTION CS,GISCABLETERM T," +
"GISFIBER F WHERE (T.ID=CS.ATERMID OR T.ID=CS.ZTERMID) AND CS.ID=F.CABLESECTIONID AND T.REGIONCODE='"+region+"')";
String countSql = "SELECT COUNT(1) AS CNT FROM GISFIBER FB WHERE FB.ID IN (SELECT DISTINCT F.ID FROM GISCABLESECTION CS,GISCABLETERM T," +
"GISFIBER F WHERE (T.ID=CS.ATERMID OR T.ID=CS.ZTERMID) AND CS.ID=F.CABLESECTIONID AND T.REGIONCODE='"+region+"')";
int count=0;
PreparedStatement delete = null;
try
{
//下载前先删除本地的纤芯数据
delete = conn_local.prepareStatement(delSql);
delete.executeUpdate();
conn_local.commit();
//统计待下载的纤芯数据总量
stmt = conn_remote.prepareStatement ( countSql ) ;
ResultSet record = stmt.executeQuery () ;
while ( record.next () )
{
count=record.getInt("CNT");
}

//之前为缓解内存溢出问题,使用了分页方法,但是好像没怎么作用
int pageSize=30000;
int iPageCount = (count + pageSize - 1) / pageSize;
if(ServerEnvironment.getDbType1().equalsIgnoreCase(GisConst.DB_POSTGRESQL)){
for (int iPage = 1; iPage <= iPageCount; iPage++) {
StringBuffer strSQL = new StringBuffer();
strSQL.append("SELECT * FROM GISFIBER FB WHERE FB.ID IN (SELECT DISTINCT F.ID FROM GISCABLESECTION CS,GISCABLETERM T,")
.append("GISFIBER F WHERE (T.ID=CS.ATERMID OR T.ID=CS.ZTERMID) AND CS.ID=F.CABLESECTIONID AND T.REGIONCODE='")
.append(region).append("')").append(" ORDER BY FB.ID LIMIT ").append(pageSize)
.append(" OFFSET ").append((iPage - 1) * pageSize);

stmt = conn_remote.prepareStatement ( strSQL.toString() ) ;
record = stmt.executeQuery () ;
YFiber fiber=null;
while ( record.next () )
{
fiber = YObjectConvertor.toFiber(record);
GisWrite.create(context, fiber);
conn_local.commit();
}
}
}else{
logger.info("Oracle数据库分页下载方法尚未补全!");
}
record.close () ;
record = null ;
}
finally
{
GisUtil.closeStatement(delete);
GisUtil.closeStatement(stmt);
}
long a1 = System.currentTimeMillis () ;
logger.info ( "纤芯数据下载完毕,共计"+count+"条记录,耗时"+ ( a1 - a0 ) +" ms" ) ;

}
...全文
396 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
喜欢HH 2015-04-29
  • 打赏
  • 举报
回复
插入数据的时候用jdbc的批处理 你可以自己定义大概多少条 往本地数据库插入一次 这样会提升很多 还有用占位符来表示参数 进行预处理sql 不用实例这么多stringbuffer connection控制自己看好 ,不用多余的开关
咖啡加蛋 2015-04-28
  • 打赏
  • 举报
回复
我没记错的话 你尝试下 执行一定的次数以后让程序休息一下 然后再继续执行,这样可以让gc有时间去释放被占用的资源
刘德龙 2014-04-15
  • 打赏
  • 举报
回复
引用 12 楼 rui888 的回复:
for (int iPage = 1; iPage <= iPageCount; iPage++) { StringBuffer strSQL = new StringBuffer(); strSQL.append("SELECT * FROM GISFIBER FB WHERE FB.ID IN (SELECT DISTINCT F.ID FROM GISCABLESECTION CS,GISCABLETERM T,") .append("GISFIBER F WHERE (T.ID=CS.ATERMID OR T.ID=CS.ZTERMID) AND CS.ID=F.CABLESECTIONID AND T.REGIONCODE='") .append(region).append("')").append(" ORDER BY FB.ID LIMIT ").append(pageSize) .append(" OFFSET ").append((iPage - 1) * pageSize); stmt = conn_remote.prepareStatement ( strSQL.toString() ) ; record = stmt.executeQuery () ; YFiber fiber=null; while ( record.next () ) { fiber = YObjectConvertor.toFiber(record); GisWrite.create(context, fiber); conn_local.commit(); } } 写在循环里 得开销很多。
那这位高手有什么好的建议吗
tony4geek 2014-04-15
  • 打赏
  • 举报
回复
for (int iPage = 1; iPage <= iPageCount; iPage++) { StringBuffer strSQL = new StringBuffer(); strSQL.append("SELECT * FROM GISFIBER FB WHERE FB.ID IN (SELECT DISTINCT F.ID FROM GISCABLESECTION CS,GISCABLETERM T,") .append("GISFIBER F WHERE (T.ID=CS.ATERMID OR T.ID=CS.ZTERMID) AND CS.ID=F.CABLESECTIONID AND T.REGIONCODE='") .append(region).append("')").append(" ORDER BY FB.ID LIMIT ").append(pageSize) .append(" OFFSET ").append((iPage - 1) * pageSize); stmt = conn_remote.prepareStatement ( strSQL.toString() ) ; record = stmt.executeQuery () ; YFiber fiber=null; while ( record.next () ) { fiber = YObjectConvertor.toFiber(record); GisWrite.create(context, fiber); conn_local.commit(); } } 写在循环里 得开销很多。
刘德龙 2014-04-15
  • 打赏
  • 举报
回复
引用 8 楼 tobbyzw 的回复:
你强制执行GC也没那么快释放掉的 你试试把占内存的对象指向NULL,然后再GC
你所谓的gc是什么意思,System.gc()吗?这个方法没用,又不是马上释放内存
刘德龙 2014-04-15
  • 打赏
  • 举报
回复
引用 7 楼 haorengoodman 的回复:
[quote=引用 5 楼 liu495777263 的回复:] [quote=引用 1 楼 haorengoodman 的回复:] 没有使用连接池吗? 如果jdbc连接数据库的话,connection需要手动释放掉, 还有数据可以分批读取,单次读取量,自己琢磨这来吧
有使用数据库,但是因为程序中现在有一次再调用多个这种类似的下载方法,如果调用一次,就close一次connection,好像也会出现问题吧?[/quote]我的意思是: 如果你使用c3p0之类的数据库连接池的话,他会自动的处理connection, 如果你是直接使用的java jdbc的话,那你就要考虑释放connection了[/quote] 我用的是 jdbc,昨晚也试着加上每次下载完关闭connection,但是内存还是没有释放,所以你还有什么别的建议吗?
wangjin9805 2014-04-14
  • 打赏
  • 举报
回复
能否用存储过程同步数据; 用代码去定义一个集合,一次读取一定数量的数据(比如1万条)放到集合中,处理集合中记录以后,再去查询下个一万条放到这个集合中,再去处理
tobbyzw 2014-04-14
  • 打赏
  • 举报
回复
你强制执行GC也没那么快释放掉的 你试试把占内存的对象指向NULL,然后再GC
haorengoodman 2014-04-14
  • 打赏
  • 举报
回复
引用 5 楼 liu495777263 的回复:
[quote=引用 1 楼 haorengoodman 的回复:] 没有使用连接池吗? 如果jdbc连接数据库的话,connection需要手动释放掉, 还有数据可以分批读取,单次读取量,自己琢磨这来吧
有使用数据库,但是因为程序中现在有一次再调用多个这种类似的下载方法,如果调用一次,就close一次connection,好像也会出现问题吧?[/quote]我的意思是: 如果你使用c3p0之类的数据库连接池的话,他会自动的处理connection, 如果你是直接使用的java jdbc的话,那你就要考虑释放connection了
刘德龙 2014-04-14
  • 打赏
  • 举报
回复
引用 4 楼 u013020442 的回复:
当然每次方法执行的时候connection都要关闭
connection有试过关闭,但是java进程占用的内存还是没有释放
刘德龙 2014-04-14
  • 打赏
  • 举报
回复
引用 1 楼 haorengoodman 的回复:
没有使用连接池吗? 如果jdbc连接数据库的话,connection需要手动释放掉, 还有数据可以分批读取,单次读取量,自己琢磨这来吧
有使用数据库,但是因为程序中现在有一次再调用多个这种类似的下载方法,如果调用一次,就close一次connection,好像也会出现问题吧?
咖啡加蛋 2014-04-14
  • 打赏
  • 举报
回复
当然每次方法执行的时候connection都要关闭
咖啡加蛋 2014-04-14
  • 打赏
  • 举报
回复
1,写一个方法,封装从远程数据库查找一页,然后本地数据库更新一页。 2,然后根据远程数据的页数进行for循环。
刘德龙 2014-04-14
  • 打赏
  • 举报
回复
自己帮顶下,也请各位路过的高手帮忙回答下。 现在程序里有很多个这种类似的下载方法,通过windows任务管理器可以看到java进程占的内存越来越大,到了规定的内存的1G之后,程序下载速度就变得很慢,再之后就内存溢出了。 赐我几个高手吧
haorengoodman 2014-04-14
  • 打赏
  • 举报
回复
没有使用连接池吗? 如果jdbc连接数据库的话,connection需要手动释放掉, 还有数据可以分批读取,单次读取量,自己琢磨这来吧

62,621

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧