jRa*_*m90 3 java firebird profiling out-of-memory
我在嵌入式firebird数据库引擎和Java SE方面遇到了很大问题.我目前正在开发一种过滤工具,供用户过滤掉数据.所以我做了两个过滤选项,用户可以选择其中一个或两个:
用户以纯文本逗号或令牌上传的数据,如下所示:
(SET OF COLUMNS)| RECORD TO FILTER |
0-MANY COLUMNS | ABC2 |
0-MANY COLUMNS | ABC5 |
Run Code Online (Sandbox Code Playgroud)
当我将其上传到数据库时,我为每个过滤器添加了一个FLAG
(SET OF COLUMNS) | RECORD TO FILTER | FLAG FOR FIlTER A | FLAG FOR FILTER B |
0-MANY COLUMNS | ABC2 | | |
0-MANY COLUMNS | ABC5 | | |
Run Code Online (Sandbox Code Playgroud)
因此,当涉及到第二个过滤器时,程序在第一次运行软件时有一个主空表,然后用第一次上载的所有记录填充该表.在用户进行一些文本上传后,主表将具有如下表所示的唯一记录:
Record | Date criteria for filtering |
ABC1 | 08/11/2012:1,07/11/2012:3,06/11/2012:5|
ABC2 | 05/11/2012:1,04/11/2012:0,03/11/2012:0|
ABC3 | 12/11/2012:3,11/11/2012:0,10/11/2012:0|
ABC4 | 12/11/2012:1,11/11/2012:0,10/11/2012:0|
ABC5 | 12/11/2012:3,11/11/2012:0,10/11/2012:3|
ABC9 | 11/11/2012:3,10/11/2012:1,09/11/2012:0|
Run Code Online (Sandbox Code Playgroud)
例如,处理数据时,软件会同时更新主表和用户表:
(SET OF COLUMNS| RECORD TO FILTER | FLAG FOR FIlTER A | FLAG FOR FILTER B |
0-MANY COLUMNS | ABC4 | | |
0-MANY COLUMNS | ABC9 | | |
Run Code Online (Sandbox Code Playgroud)
所以主表将更新:
Record | Day criteria for filtering |
ABC1 | 08/11/2012:1,07/11/2012:3,06/11/2012:5|
ABC2 | 05/11/2012:1,04/11/2012:0,03/11/2012:0|
ABC3 | 12/11/2012:3,11/11/2012:0,10/11/2012:0|
ABC4 | 12/11/2012:1,11/11/2012:0,10/11/2012:0| ->12/11/2012:2,11/11/2012:0,10/11/2012:0
ABC5 | 12/11/2012:3,11/11/2012:0,10/11/2012:3|
ABC9 | 11/11/2012:3,10/11/2012:1,09/11/2012:0| ->12/11/2012:1,11/11/2012:3,10/11/2012:1
Run Code Online (Sandbox Code Playgroud)
如果在过去三天内数据条件事件已达到四个以上,则用户表将标记过滤器B.请注意,每个日期旁边都有一个整数.
(SET OF COLUMNS)| RECORD TO FILTER | FLAG FOR FIlTER A | FLAG FOR FILTER B |
0-MANY COLUMNS | ABC4 | | |
0-MANY COLUMNS | ABC9 | | X |
Run Code Online (Sandbox Code Playgroud)
两个更新都在一个事务中,问题是当用户上传超过800,000条记录时,我的程序在while循环中抛出以下异常.我使用StringBuilder解析并附加方法,以便在可变天数字符串上实现最大性能.
java.lang.OutOfMemoryError:Java堆空间
这是我的代码,我使用了五天:
FactoriaDeDatos factoryInstace = FactoriaDeDatos.getInstance();
Connection cnx = factoryInstace.getConnection();
cnx.setAutoCommit(false);
PreparedStatement pstmt = null;
ResultSet rs=null;
pstmt = cnx.prepareStatement("SELECT CM.MAIL,CM.FECHAS FROM TCOMERCIALMAIL CM INNER JOIN TEMPMAIL TMP ON CM.MAIL=TMP."+colEmail);
rs=pstmt.executeQuery();
pstmtDet = cnx.prepareStatement("ALTER INDEX IDX_MAIL INACTIVE");
pstmtDet.executeUpdate();
pstmtDet = cnx.prepareStatement("SET STATISTICS INDEX IDX_FECHAS");
pstmtDet.executeUpdate();
pstmtDet = cnx.prepareStatement("ALTER INDEX IDX_FECHAS INACTIVE");
pstmtDet.executeUpdate();
pstmtDet = cnx.prepareStatement("SET STATISTICS INDEX IDX_FECHAS");
pstmtDet.executeUpdate();
sql_com_local_tranx=0;
int trxNum=0;
int ix=0;
int ixE1=0;
int ixAc=0;
StringBuilder sb;
StringTokenizer st;
String fechas;
int pos1,pos2,pos3,pos4,pos5,pos6,pos7,pos8,pos9;
StringBuilder s1,s2,sSQL,s4,s5,s6,s7,s8,s9,s10;
long startLoop = System.nanoTime();
long time2 ;
boolean ejecutoMax=false;
//int paginador_sql=1000;
//int trx_ejecutada=0;
sb=new StringBuilder();
s1=new StringBuilder();
s2=new StringBuilder();
sSQL=new StringBuilder();
s4=new StringBuilder();
s6=new StringBuilder();
s8=new StringBuilder();
s10=new StringBuilder();
while(rs.next()){
//De aqui
actConteoDia=0;
sb.setLength(0);
sb.append(rs.getString(2));
pos1= sb.indexOf(":",0);
pos2= sb.indexOf(",",pos1+1);
pos3= sb.indexOf(":",pos2+1);
pos4= sb.indexOf(",",pos3+1);
pos5= sb.indexOf(":",pos4+1);
pos6= sb.indexOf(",",pos5+1);
pos7= sb.indexOf(":",pos6+1);
pos8= sb.indexOf(",",pos7+1);
pos9= sb.indexOf(":",pos8+1);
s1.setLength(0);
s1.append(sb.substring(0, pos1));
s2.setLength(0);
s2.append(sb.substring(pos1+1, pos2));
s4.setLength(0);
s4.append(sb.substring(pos3+1, pos4));
s6.setLength(0);
s6.append(sb.substring(pos5+1, pos6));
s8.setLength(0);
s8.append(sb.substring(pos7+1, pos8));
s10.setLength(0);
s10.append(sb.substring(pos9+1));
actConteoDia=Integer.parseInt(s2.toString());
actConteoDia++;
sb.setLength(0);
//sb.append(s1).a
if(actConteoDia>MAXIMO_LIMITE_POR_SEMANA){
actConteoDia=MAXIMO_LIMITE_POR_SEMANA+1;
}
sb.append(s1).append(":").append(actConteoDia).append(",").append(rs.getString(2).substring(pos2+1, rs.getString(2).length()));
//For every date record it takes aprox 8.3 milisec by record
sSQL.setLength(0);
sSQL.append("UPDATE TCOMERCIALMAIL SET FECHAS='").append(sb.toString()).append("' WHERE MAIL='").append(rs.getString(1)).append("'");
pstmtDet1.addBatch(sSQL.toString());
//actConteoDia=0;
//actConteoDia+=Integer.parseInt(s2.toString());
actConteoDia+=Integer.parseInt(s4.toString());
actConteoDia+=Integer.parseInt(s6.toString());
actConteoDia+=Integer.parseInt(s8.toString());
actConteoDia+=Integer.parseInt(s10.toString());
if(actConteoDia>MAXIMO_LIMITE_POR_SEMANA){
sSQL.setLength(0);
sSQL.append("UPDATE TEMPMAIL SET DIASLIMITE='S' WHERE ").append(colEmail).append("='").append(rs.getString(1)).append("'");
pstmtDet.addBatch(sSQL.toString());
}
sql_com_local_tranx++;
if(sql_com_local_tranx%2000==0 || sql_com_local_tranx%7000==0 ){
brDias.setString("PROCESANDO "+sql_com_local_tranx);
pstmtDet1.executeBatch();
pstmtDet.executeBatch();
}
if(sql_com_local_tranx%100000==0){
System.gc();
System.runFinalization();
}
}
pstmtDet1.executeBatch();
pstmtDet.executeBatch();
cnx.commit();
Run Code Online (Sandbox Code Playgroud)
我已经进行了遥测测试,因此我可以追踪问题所在.我认为,这是问题的重要时刻,但我不知道问题究竟在哪里.我正在添加远程测试的一些图像,请我正确地解释它们.
gc与jvm保持对象存活的时间相反:
http://imageshack.us/photo/my-images/849/66780403.png
内存堆从50 MB到250 MB,使用的堆达到250 MB,创建outOfMemory异常:
50 MB
http://imageshack.us/photo/my-images/94/52169259.png
达到250 MB
http://imageshack.us/photo/my-images/706/91313357.png
内存
不足http://imageshack.us/photo/my-images/825/79083069.png
LiveBytes生成的最终生成的objet集合:
http://imageshack.us/photo/my-images/546/95529690.png
任何帮助,建议和答案都将非常感激.
问题是,你正在使用PreparedStatement,就好像它是一个Statement,因为你在呼唤addBatch(string).这种方法的javadoc说:
注意:无法在PreparedStatement或CallableStatement上调用此方法.
这个评论是在JDBC 4.0中添加的,之前它说该方法是可选的.Jaybird允许您调用此方法的事实PreparedStatement就是一个错误:我在Jaybird跟踪器中创建了问题JDBC-288.
现在的原因是OutOfMemoryError:当你使用Jaybird()addBatch(String)的PreparedStatement实现时FBPreparedStatement,它被添加到Statementimplementation(FBStatement)内部的列表中.在情况下FBStatement,当你调用executeBatch(),它将执行在此列表中的所有语句,然后将其清除.在FBPreparedStatement但是executeBatch()被覆盖到执行与批处理参数原本准备语句(在你的例子也不会做任何事情,因为你从来没有真正加入一个PreparedStatement式批次).它永远不会执行你添加的语句addBatch(String),但它也不会清除语句列表,FBStatement这很可能是你的原因OutOfMemoryError.
基于此,解决方案应该是创建Statement使用cnx.createStatement并使用它来执行查询,或者调查是否可以通过PreparedStatement参数化查询使用一个或多个对象.看起来你应该可以使用两个单独的PreparedStatements,但我不是100%肯定; 增加的好处是防止SQL注入和轻微的性能改进.
自Jaybird 2.2.2以来,此问题已得到修复
完全披露:我是Jaybird/Firebird JDBC驱动程序的开发人员.
| 归档时间: |
|
| 查看次数: |
516 次 |
| 最近记录: |