问题出在构造XML 的Document 上,Element.getElementsByTagName( String name ).item( int index ).appendChild( Document.createTextNode( String data ))这个构造XML文本节点的方法奇耗内存还奇慢无比!
来看看代码: package db2xml;/** * <p>Title: </p> * <p>Description: </p> * <p>Copyright: Copyright (c) 2004</p> * <p>Company: </p> * @author not attributable * @version 1.0 */ import java.io.*; import org.jdom.*; import org.jdom.input.*; import org.jdom.output.*; import java.util.*; import java.awt.*; import java.sql.*; import java.lang.StringBuffer; import java.lang.Runtime;public class saveDataAsXml extends SQLManagerBean { Statement stmt = null; Connection conn = null; //ResultSet rs = null; querytableDBFrame query = new querytableDBFrame(); //connDB db = new connDB(); public saveDataAsXml(querytableDBFrame q) { query = q; } public void save(String fileName,String s,String s1,String table) { Document document = null; String sql = s; try{ //connDB connDB = null; // try { // if(conn == null){ //conn = connDB.getConnection(); //连接数据库 // } // } // catch (IOException ex1) { // } //根据表名称保存为flowName.xml //检验表名称是否重复 if (query == null) return; // String xmlFileName="save/"+flow.getFlowName()+".xml"; String xmlFileName=fileName + ".xml"; File f = new File(xmlFileName); if (f.exists()) { int sel = javax.swing.JOptionPane.showConfirmDialog(null, fileName + " 已存在,是否覆盖已有表文件?", "提示", javax.swing.JOptionPane.YES_NO_OPTION); if (sel != 0) return; } int count = super.getRowCount(s1); System.out.println(count); //System.out.println("mod"+ 24/12); if(count > 5000){ for(int i=0;i<=(count/5000);i++){ int start = i*5000; int end = i*5000+5000; if(end >= count){ end = count; } System.out.println("end" +end); document = createDoc(sql,start,end); String fileName1 = fileName + "_" + i + ".xml"; outxml(document, fileName1); query.result.append(fileName1); query.result.append("\n"); document = null; System.gc(); //fileName = null; } }else{ document = this.createDoc(sql); fileName = fileName + ".xml"; outxml(document, fileName); document = null; System.gc(); query.result.append(fileName); query.result.append("\n"); } //notifyAll(); System.gc(); //rs.close(); //stmt.close(); //conn.close(); }catch (Exception ex) { System.out.println("save的error"+ex.getMessage()); } } public Document createDoc(String sql){ Element root = null; try{ //stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, // ResultSet.CONCUR_READ_ONLY); ResultSet rs = super.executeQuery(sql); //System.out.println(sql); root = new Element("ROOT"); ResultSetMetaData rsmd = rs.getMetaData(); //获取字段名 int numberOfColumns = rsmd.getColumnCount(); //获取字段数 int i = 0; while (rs.next()) { Element element0 = new Element("ELEMENT"); //创建元素 生成JDOM树 for (i = 1; i <= numberOfColumns; i++) { try { String date=rs.getString(i); //query.result.append(date); // query.result.append("\n"); Element element = new Element(rsmd.getColumnName(i)).setText(date); element0.addContent(element); } catch (Exception e) { System.out.println(e.getMessage() + e.toString()); } } root.addContent(element0); } rs.close(); //stmt.close(); //conn.close(); }catch(SQLException ex){ System.out.println("ex"+ex); } Document doc=new Document(root); return doc; } public Document createDoc(String sql,int start,int end){ Element root = null; ResultSet rs2 = null; String[][] result = null; Element element0 = null; Element element = null; try{ //stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, //ResultSet.CONCUR_READ_ONLY); if(rs2 != null) rs2.close(); rs2 = super.executeQuery(sql); System.out.println(sql); root = new Element("ROOT"); ResultSetMetaData rsmd = rs2.getMetaData(); //获取字段名 int numberOfColumns = rsmd.getColumnCount(); //获取字段数 //int i = 0; result = new String[end-start][numberOfColumns]; result = super.execSql(sql,start,end); System.out.println("start"+start+"end"+end); //System.out.println("result"+result[0][0]); //while (rs.next()) for(int i = 0; i < end-start; i++){ element0 = new Element("ELEMENT"); //创建元素 生成JDOM树 for (int j = 0; j < numberOfColumns; j++) { try { //System.out.println("start"+start+"end"+end); String date = result[i][j]; // System.out.println("result["+i+"]["+j+"]" + result[i][j]); //query.result.append(date); // query.result.append("\n"); element = new Element(rsmd.getColumnName(j+1)).setText(date); element0.addContent(element); } catch (Exception e) { System.out.println(e.getMessage() + e.toString()); } } root.addContent(element0); //result = null; } result = null; // rs2.close(); // stmt.close(); // conn.close(); }catch(SQLException ex){ System.out.println("creatdoc的error" + ex.getNextException()); } Document doc=new Document(root); return doc; } public static void outxml(Document document,String fileName){ if (document != null){ XMLOutputter outp = new XMLOutputter(); try { FileOutputStream writer = new FileOutputStream(fileName); outp.setEncoding("iso_8859_1"); outp.output(document, writer); writer.close(); } catch (IOException ex2) { ex2.printStackTrace(); } } } public static void RunExe(){ try{ String command = "cmd.exe /c start c:/test.bat"; Process child = Runtime.getRuntime().exec(command); } catch(Exception e){ e.printStackTrace(); } } }
这样我把数据库连接池也发出来.... package db2xml;import java.io.*; import java.sql.*; import java.util.*; import java.util.Date;public class DBManager{ static private DBManager instance; // 唯一实例 static private int clients; private Vector drivers = new Vector(); private PrintWriter log; private Hashtable pools = new Hashtable(); static public String poolName=""; static public String libname=""; static public String asflag=""; static public String dbName=""; static public String deptflag=""; static synchronized public DBManager getInstance() { if(instance == null) { instance = new DBManager(); System.out.println("新创建DBManager实例"); } clients++; System.out.println("当前客户连接位置clients="+clients); return instance; } private DBManager() { init(); } public void freeConnection(String name, Connection con) { DBConnectionPool pool = (DBConnectionPool) pools.get(name); if (pool != null) { pool.freeConnection(con); //System.out.println("返回一个连接回连接池"); } } public Connection getConnection(String name) { DBConnectionPool pool = (DBConnectionPool) pools.get(name); if (pool != null) { //System.out.println("得到一个连接回连接池"); return pool.getConnection(); } return null; } public Connection getConnection(String name, long time) { DBConnectionPool pool = (DBConnectionPool) pools.get(name); if (pool != null) { //System.out.println("得到一个有时间限制的连接回连接池"); return pool.getConnection(time); } return null; } public synchronized void release() { // 等待直到最后一个客户程序调用 if (--clients != 0) { return; } Enumeration allPools = pools.elements(); while (allPools.hasMoreElements()) { DBConnectionPool pool = (DBConnectionPool) allPools.nextElement(); pool.release(); } Enumeration allDrivers = drivers.elements(); while (allDrivers.hasMoreElements()) { Driver driver = (Driver) allDrivers.nextElement(); try { DriverManager.deregisterDriver(driver); log("撤销JDBC驱动程序 " + driver.getClass().getName()+"的注册"); }catch (SQLException e) { log(e, "无法撤销下列JDBC驱动程序的注册: " + driver.getClass().getName()); } } } private void createPools(Properties props) { Enumeration propNames = props.propertyNames(); while (propNames.hasMoreElements()) { String name = (String) propNames.nextElement(); if (name.endsWith(".url")) { poolName = name.substring(0, name.lastIndexOf(".")); String url = props.getProperty(poolName + ".url"); if (url == null) { log("没有为连接池" + poolName + "指定URL"); continue; } String user = props.getProperty(poolName + ".user"); String password = props.getProperty(poolName + ".password"); String maxconn = props.getProperty(poolName + ".maxconn", "0"); libname=props.getProperty(poolName+".libname"); asflag=props.getProperty(poolName+".flag"); dbName=props.getProperty(poolName+".dbname"); deptflag=props.getProperty(poolName+".dept"); int max; try { max = Integer.valueOf(maxconn).intValue(); }catch (NumberFormatException e) { log("错误的最大连接数限制: " + maxconn + " .连接池: " + poolName); max = 0; } DBConnectionPool pool = new DBConnectionPool(poolName, url, user, password, max); pools.put(poolName, pool); log("成功创建连接池" + poolName); } } } private void init() { //InputStream is = getClass().getResourceAsStream("./dbconfig.ini"); FileInputStream is = null; try { is = new FileInputStream("database.properties"); } catch (FileNotFoundException ex) { System.out.print("文件没有找到"); } Properties dbProps = new Properties(); try { dbProps.load(is); System.out.println("读取dbConfig.ini成功"); }catch (Exception e) { return; } String logFile = dbProps.getProperty("logfile", "DBManager.log"); try { log = new PrintWriter(new FileWriter(logFile, true), true); }catch (IOException e) { log = new PrintWriter(System.err); } loadDrivers(dbProps); createPools(dbProps); } private void loadDrivers(Properties props) { String driverClasses = props.getProperty("drivers"); StringTokenizer st = new StringTokenizer(driverClasses); while (st.hasMoreElements()) { String driverClassName = st.nextToken().trim(); try { Driver driver = (Driver) Class.forName(driverClassName).newInstance(); DriverManager.registerDriver(driver); drivers.addElement(driver); log("成功注册JDBC驱动程序" + driverClassName); log("成功注册JDBC驱动程序"); }catch (Exception e) { log("无法注册JDBC驱动程序: " + driverClassName + ", 错误: " + e); } } } private void log(String msg) { log.println(new Date() + ": " + msg); } private void log(Throwable e, String msg) { log.println(new Date() + ": " + msg); e.printStackTrace(log); }
Xincgc增加回收线程级别,jc()方法不是回收是建议JVM回收。 java -Xmx400m -Xincgc TestMemory 这样,你的JVM的内存就可以被操作系统回收了下面是-X参数说明 C:\>java -X -Xmixed mixed mode execution (default) -Xint interpreted mode execution only -Xbootclasspath:<directories and zip/jar files separated by ;> set search path for bootstrap classes and resources -Xbootclasspath/a:<directories and zip/jar files separated by ;> append to end of bootstrap class path -Xbootclasspath/p:<directories and zip/jar files separated by ;> prepend in front of bootstrap class path -Xnoclassgc disable class garbage collection -Xincgc enable incremental garbage collection -Xloggc:<file> log GC status to a file with time stamps -Xbatch disable background compilation -Xms<size> set initial Java heap size -Xmx<size> set maximum Java heap size -Xss<size> set java thread stack size -Xprof output cpu profiling data -Xrunhprof[:help]|[:<option>=<value>, ...] perform JVMPI heap, cpu, or monitor profiling -Xdebug enable remote debugging -Xfuture enable strictest checks, anticipating future default -Xrs reduce use of OS signals by Java/VM (see documentation) -Xcheck:jni perform additional checks for JNI functionsThe -X options are non-standard and subject to change without notice.
zhang21cnboy(事了抚衣去,不留身与名)另外吧你的rs不要设置为可以回滚的那种。
====================================================这个会有问题吗?回滚应该是数据库提供的,那样不会占用内存吧。
我没有试过,楼上的你确信回滚会有问题吗?
你肯定有循环,在一次循环的大量操作前,手动垃圾收集,然后wait一会儿,也就几百个ms,慢慢来!让他收集了,反正也使数据转移,效率不是问题!
第二,对于超大型数据转换,你的这种做法效率太低。
应该直接用native sql 倒成2进制文件(假设是同类型数据库)或文本文件(不同类型数据库),
再传输压缩后的文件。
当效率成为首要问题时,不应该考虑使用xml了。
第三,如果你的应用需要这样频繁转移如此大的数据,基本可以断定你的整个系统设计都有问题。
package db2xml;/**
* <p>Title: </p>
* <p>Description: </p>
* <p>Copyright: Copyright (c) 2004</p>
* <p>Company: </p>
* @author not attributable
* @version 1.0
*/
import java.io.*;
import org.jdom.*;
import org.jdom.input.*;
import org.jdom.output.*;
import java.util.*;
import java.awt.*;
import java.sql.*;
import java.lang.StringBuffer;
import java.lang.Runtime;public class saveDataAsXml extends SQLManagerBean {
Statement stmt = null;
Connection conn = null;
//ResultSet rs = null;
querytableDBFrame query = new querytableDBFrame();
//connDB db = new connDB(); public saveDataAsXml(querytableDBFrame q) {
query = q;
} public void save(String fileName,String s,String s1,String table) {
Document document = null;
String sql = s;
try{
//connDB connDB = null;
// try {
// if(conn == null){
//conn = connDB.getConnection(); //连接数据库
// }
// }
// catch (IOException ex1) {
// }
//根据表名称保存为flowName.xml
//检验表名称是否重复
if (query == null)
return;
// String xmlFileName="save/"+flow.getFlowName()+".xml";
String xmlFileName=fileName + ".xml";
File f = new File(xmlFileName);
if (f.exists()) {
int sel = javax.swing.JOptionPane.showConfirmDialog(null,
fileName + " 已存在,是否覆盖已有表文件?", "提示",
javax.swing.JOptionPane.YES_NO_OPTION);
if (sel != 0)
return;
} int count = super.getRowCount(s1);
System.out.println(count);
//System.out.println("mod"+ 24/12);
if(count > 5000){
for(int i=0;i<=(count/5000);i++){
int start = i*5000;
int end = i*5000+5000;
if(end >= count){
end = count;
}
System.out.println("end" +end);
document = createDoc(sql,start,end);
String fileName1 = fileName + "_" + i + ".xml";
outxml(document, fileName1);
query.result.append(fileName1);
query.result.append("\n");
document = null;
System.gc();
//fileName = null;
}
}else{
document = this.createDoc(sql);
fileName = fileName + ".xml";
outxml(document, fileName);
document = null;
System.gc();
query.result.append(fileName);
query.result.append("\n");
}
//notifyAll();
System.gc();
//rs.close();
//stmt.close();
//conn.close();
}catch (Exception ex) {
System.out.println("save的error"+ex.getMessage());
}
}
public Document createDoc(String sql){
Element root = null;
try{
//stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
// ResultSet.CONCUR_READ_ONLY);
ResultSet rs = super.executeQuery(sql);
//System.out.println(sql);
root = new Element("ROOT");
ResultSetMetaData rsmd = rs.getMetaData(); //获取字段名
int numberOfColumns = rsmd.getColumnCount(); //获取字段数
int i = 0;
while (rs.next()) {
Element element0 = new Element("ELEMENT"); //创建元素 生成JDOM树
for (i = 1; i <= numberOfColumns; i++) {
try {
String date=rs.getString(i);
//query.result.append(date);
// query.result.append("\n");
Element element = new Element(rsmd.getColumnName(i)).setText(date);
element0.addContent(element);
}
catch (Exception e) {
System.out.println(e.getMessage() + e.toString());
}
}
root.addContent(element0);
}
rs.close();
//stmt.close();
//conn.close();
}catch(SQLException ex){
System.out.println("ex"+ex);
}
Document doc=new Document(root);
return doc;
}
public Document createDoc(String sql,int start,int end){
Element root = null;
ResultSet rs2 = null;
String[][] result = null;
Element element0 = null;
Element element = null;
try{
//stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
//ResultSet.CONCUR_READ_ONLY);
if(rs2 != null) rs2.close();
rs2 = super.executeQuery(sql);
System.out.println(sql);
root = new Element("ROOT");
ResultSetMetaData rsmd = rs2.getMetaData(); //获取字段名
int numberOfColumns = rsmd.getColumnCount(); //获取字段数
//int i = 0;
result = new String[end-start][numberOfColumns];
result = super.execSql(sql,start,end);
System.out.println("start"+start+"end"+end);
//System.out.println("result"+result[0][0]);
//while (rs.next())
for(int i = 0; i < end-start; i++){
element0 = new Element("ELEMENT"); //创建元素 生成JDOM树
for (int j = 0; j < numberOfColumns; j++) {
try {
//System.out.println("start"+start+"end"+end);
String date = result[i][j];
// System.out.println("result["+i+"]["+j+"]" + result[i][j]);
//query.result.append(date);
// query.result.append("\n");
element = new Element(rsmd.getColumnName(j+1)).setText(date);
element0.addContent(element);
}
catch (Exception e) {
System.out.println(e.getMessage() + e.toString());
}
}
root.addContent(element0);
//result = null;
}
result = null;
// rs2.close();
// stmt.close();
// conn.close();
}catch(SQLException ex){
System.out.println("creatdoc的error" + ex.getNextException());
}
Document doc=new Document(root);
return doc;
} public static void outxml(Document document,String fileName){
if (document != null){
XMLOutputter outp = new XMLOutputter();
try {
FileOutputStream writer = new FileOutputStream(fileName);
outp.setEncoding("iso_8859_1");
outp.output(document, writer);
writer.close();
}
catch (IOException ex2) {
ex2.printStackTrace();
}
}
} public static void RunExe(){
try{
String command = "cmd.exe /c start c:/test.bat";
Process child = Runtime.getRuntime().exec(command);
}
catch(Exception e){
e.printStackTrace();
}
}
}
==================================================== zhang21cnboy(事了抚衣去,不留身与名)另外吧你的rs不要设置为可以回滚的那种。
====================================================这个会有问题吗?回滚应该是数据库提供的,那样不会占用内存吧。
我没有试过,楼上的你确信回滚会有问题吗?
package db2xml;import java.io.*;
import java.sql.*;
import java.util.*;
import java.util.Date;public class DBManager{
static private DBManager instance; // 唯一实例
static private int clients; private Vector drivers = new Vector();
private PrintWriter log;
private Hashtable pools = new Hashtable();
static public String poolName="";
static public String libname="";
static public String asflag="";
static public String dbName="";
static public String deptflag=""; static synchronized public DBManager getInstance() {
if(instance == null)
{
instance = new DBManager();
System.out.println("新创建DBManager实例");
}
clients++;
System.out.println("当前客户连接位置clients="+clients);
return instance;
} private DBManager() {
init();
} public void freeConnection(String name, Connection con) {
DBConnectionPool pool = (DBConnectionPool) pools.get(name);
if (pool != null) {
pool.freeConnection(con);
//System.out.println("返回一个连接回连接池");
}
} public Connection getConnection(String name) {
DBConnectionPool pool = (DBConnectionPool) pools.get(name);
if (pool != null) {
//System.out.println("得到一个连接回连接池");
return pool.getConnection();
}
return null;
} public Connection getConnection(String name, long time) {
DBConnectionPool pool = (DBConnectionPool) pools.get(name);
if (pool != null) {
//System.out.println("得到一个有时间限制的连接回连接池");
return pool.getConnection(time);
}
return null;
} public synchronized void release() {
// 等待直到最后一个客户程序调用
if (--clients != 0) {
return;
} Enumeration allPools = pools.elements();
while (allPools.hasMoreElements()) {
DBConnectionPool pool = (DBConnectionPool) allPools.nextElement();
pool.release();
}
Enumeration allDrivers = drivers.elements();
while (allDrivers.hasMoreElements()) {
Driver driver = (Driver) allDrivers.nextElement();
try {
DriverManager.deregisterDriver(driver);
log("撤销JDBC驱动程序 " + driver.getClass().getName()+"的注册");
}catch (SQLException e) {
log(e, "无法撤销下列JDBC驱动程序的注册: " + driver.getClass().getName());
}
}
} private void createPools(Properties props) {
Enumeration propNames = props.propertyNames();
while (propNames.hasMoreElements()) {
String name = (String) propNames.nextElement();
if (name.endsWith(".url")) {
poolName = name.substring(0, name.lastIndexOf(".")); String url = props.getProperty(poolName + ".url");
if (url == null) {
log("没有为连接池" + poolName + "指定URL");
continue;
}
String user = props.getProperty(poolName + ".user");
String password = props.getProperty(poolName + ".password");
String maxconn = props.getProperty(poolName + ".maxconn", "0");
libname=props.getProperty(poolName+".libname");
asflag=props.getProperty(poolName+".flag");
dbName=props.getProperty(poolName+".dbname");
deptflag=props.getProperty(poolName+".dept"); int max;
try {
max = Integer.valueOf(maxconn).intValue();
}catch (NumberFormatException e) {
log("错误的最大连接数限制: " + maxconn + " .连接池: " + poolName);
max = 0;
}
DBConnectionPool pool = new DBConnectionPool(poolName, url, user, password, max);
pools.put(poolName, pool);
log("成功创建连接池" + poolName);
}
}
} private void init() {
//InputStream is = getClass().getResourceAsStream("./dbconfig.ini");
FileInputStream is = null;
try {
is = new FileInputStream("database.properties");
}
catch (FileNotFoundException ex) {
System.out.print("文件没有找到");
} Properties dbProps = new Properties();
try {
dbProps.load(is);
System.out.println("读取dbConfig.ini成功");
}catch (Exception e) {
return;
}
String logFile = dbProps.getProperty("logfile", "DBManager.log");
try {
log = new PrintWriter(new FileWriter(logFile, true), true);
}catch (IOException e) {
log = new PrintWriter(System.err);
}
loadDrivers(dbProps);
createPools(dbProps);
} private void loadDrivers(Properties props) {
String driverClasses = props.getProperty("drivers");
StringTokenizer st = new StringTokenizer(driverClasses);
while (st.hasMoreElements()) {
String driverClassName = st.nextToken().trim();
try {
Driver driver = (Driver)
Class.forName(driverClassName).newInstance();
DriverManager.registerDriver(driver);
drivers.addElement(driver);
log("成功注册JDBC驱动程序" + driverClassName);
log("成功注册JDBC驱动程序");
}catch (Exception e) {
log("无法注册JDBC驱动程序: " + driverClassName + ", 错误: " + e);
}
}
} private void log(String msg) {
log.println(new Date() + ": " + msg);
}
private void log(Throwable e, String msg) {
log.println(new Date() + ": " + msg);
e.printStackTrace(log);
}
java -Xmx400m -Xincgc TestMemory
这样,你的JVM的内存就可以被操作系统回收了下面是-X参数说明
C:\>java -X
-Xmixed mixed mode execution (default)
-Xint interpreted mode execution only
-Xbootclasspath:<directories and zip/jar files separated by ;>
set search path for bootstrap classes and resources
-Xbootclasspath/a:<directories and zip/jar files separated by ;>
append to end of bootstrap class path
-Xbootclasspath/p:<directories and zip/jar files separated by ;>
prepend in front of bootstrap class path
-Xnoclassgc disable class garbage collection
-Xincgc enable incremental garbage collection
-Xloggc:<file> log GC status to a file with time stamps
-Xbatch disable background compilation
-Xms<size> set initial Java heap size
-Xmx<size> set maximum Java heap size
-Xss<size> set java thread stack size
-Xprof output cpu profiling data
-Xrunhprof[:help]|[:<option>=<value>, ...]
perform JVMPI heap, cpu, or monitor profiling
-Xdebug enable remote debugging
-Xfuture enable strictest checks, anticipating future default
-Xrs reduce use of OS signals by Java/VM (see documentation)
-Xcheck:jni perform additional checks for JNI functionsThe -X options are non-standard and subject to change without notice.
java -Xmx400m -Xincgc TestMemory这里的TestMemory是什么?
2. 你的rs, statement, conn释放得不干净
研究 Java 中 XML 文档模型的特性和性能
不同的 Java XML 文档模型各有所长,但是从性能观点来看,有些模型具有明显的优势。在大多数方面,XPP 性能处于领先地位。尽管 XPP 是一种新模型,但是对于不需要验证、实体、处理指示信息或注释的中间件类型应用程序来说,它是非常好的选择。它尤其适用于作为浏览器小应用程序或在内存受限的环境下运行的应用程序。虽然 dom4j 没有与 XPP 同等的速度,但是,它确实提供了具备更标准化的优越性能和功能更全的实现,包括对 SAX2、DOM 甚至 XPath 的内置支持。虽然 Xerces DOM(带有延迟的节点创建)对于小文件和 Java 序列化性能不佳,但是在大多数评测时仍然出色。对于常规 XML 处理,dom4j 和 Xerces DOM 都是很好的选择,对它们的选择取决于您认为是特定于 Java 的特性更重要还是跨语言的兼容性更重要。JDOM 和 Crimson DOM 在性能测试时一直表现不佳。在小文档情况下还值得考虑使用 Crimson DOM,而 Xerces 表现很差。虽然 JDOM 的开发者已经说明他们期望在正式发行版前专注性能问题,但是从性能观点来看,它确实没有值得推荐之处。然而,如果不进行 API 的重新构建,JDOM 可能难以达到与其它模型匹配的性能。EXML 非常小(以 jar 文件大小为单位)并且在一些性能测试中表现良好。虽然 EXML 具有删除单独空白内容的优势,但是在性能方面不如 XPP。除非您需要 EXML 支持而 XPP 缺少的一种特性,否则在内存受限的环境下,XPP 可能是更好的选择。虽然 dom4j 性能最好,但是,当前没有一种模型能为 Java 序列化提供良好性能。如果需要在程序之间传递文档,通常的最佳选择是将文档写成文本然后进行解析以重新构建表示。将来,定制序列化格式可能提供一个更好的选择。