我正在阅读一些大型XML文件并将它们存储到数据库中。它是800 mb。
它会存储许多记录,然后终止并提供例外:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.IdentityHashMap.resize(Unknown Source)
at java.util.IdentityHashMap.put(Unknown Source)
使用Memory Analyzer我创建了.hprof文件,其中包含:
76,581 instances of "java.lang.String", loaded by "<system class loader>" occupy 1,04,34,45,504 (98.76%) bytes.
Keywords
java.lang.String
我有用于检索值的setter和getter。我如何解决此问题。任何帮助都会被贬低。
我通过 JRE 。 ini 增加了记忆力。但问题没有解决
编辑:我使用scireumOpen来读取XML文件。
我使用的示例代码:
public void readD() throws Exception {
XMLReader reader = new XMLReader();
reader.addHandler("node", new NodeHandler() {
@Override
public void process(StructuredNode node) {
try {
obj.setName(node
.queryString("name"));
save(obj);
} catch (XPathExpressionException xPathExpressionException) {
xPathExpressionException.printStackTrace();
} catch (Exception exception) {
exception.printStackTrace();
}
}
});
reader.parse(new FileInputStream(
"C:/Users/some_file.xml"));
}
public void save(Reader obj) {
try {
EntityTransaction entityTransaction = em.getTransaction();
entityTransaction.begin();
Entity e1=new Entity;
e1.setName(obj.getName());
em.persist(e1);
entityTransaction.commit();
} catch (Exception exception) {
exception.printStackTrace();
}
}
答案 0 :(得分:5)
尝试使用另一个解析器进行XML处理。
使用例如800M处理一个大的XML文件DOM
不可行,因为它占用了很多内存。
尝试在Java中使用SAX
ot StAX
并立即处理解析结果,而不尝试将完整的XML文件加载到内存中。
并且也不要将解析结果保留在内存中。尽可能快地将它们写入数据库并尽可能缩小解析结果的范围。
也许在数据库中使用中间表并对数据库内的所有数据集执行处理部分。
答案 1 :(得分:2)
答案 2 :(得分:1)
java -XmxNN
SAXParser
而不是DOM
树(如果您不这样做的话)。这取决于您的应用程序设计,因此您必须查看它并查看这是否是一种可能的策略。null
。在不知道您的代码的情况下,这只是一般指导。
答案 3 :(得分:1)
我的主要提示:再次检查您的JPA代码。应该尽可能孤立。
一个想法是使用带注释的JAXB。 IdentityHashMap(键使用==
而不是equals
)是罕见的,可能是JPA,也许是XML标签?您还可以查看使用的XML解析器(检查工厂类,或者通过java SPI,服务提供者接口列出所有XML解析器提供程序)。
您可以共享字符串,例如长度小于20的所有字符串。使用Map<String, String>
。
private Map<String, String> sharedStrings = new HashMap<>();
private String shareString(String s) {
if (s == null || s.length() > 20) {
return s;
}
String t = sharedStrings.get(s);
if (t == null) {
t = s;
sharedStrings.put(t, t);
}
return t;
}
public void setXxx(String xxx) {
this.xxx = sharedString(xxx);
}
您可以对bean中的较大文本使用压缩(GZip流)。
答案 4 :(得分:1)
如果您正在使用,请不要使用String
。请将其置于StringBuffer
或StringBuilder
。此外,请尝试增加内存。我猜2048可以,但如果问题仍然存在,然后改为4096米甚至尝试6000米
答案 5 :(得分:0)
启动Java时可以增加堆大小:
java -Xmx8G
答案 6 :(得分:0)
看起来你在发布之前编辑代码,或发布不完全正确的代码。请更正。
首先,您的代码不会编译。
其次,不要在save
函数中传递Reader。在process(StructuredNode node)
中创建并填充实体并传递实体,而不是Reader,以保存功能。
第三,正确处理save
函数中的异常。如果发生异常,则回滚事务。
答案 7 :(得分:0)
最后我解决了我的问题。 以下事情有所帮助:
1。堆大小2048就足够了。
2。另一个问题是我使用的是字符串。
和字符串对象是不可变的
通过immutable,我们的意思是不能更改存储在String对象中的值。然后我们想到的下一个问题是“如果String是不可变的那么我怎么能随时改变对象的内容?”。好吧,确切地说,它不是反映您所做更改的相同String对象。在内部创建一个新的String对象来进行更改。
参考Difference between string and stringbuffer, Stringbuilder
所以我删除了JPA实体以外的实体的getter和setter。并将所有数据直接插入到数据库中,而不将其设置为任何对象。
3. 第三个主要问题是 JPAEntityManager 。
我的代码无法确保方法完成时EntityManager始终处于关闭状态。 至于业务逻辑中发生RuntimeException,em EntityManager仍保持打开状态!
所以总是关闭它,你也可以在finally块中将对象设置为null,如
finally {
Obj1 = null;
Obj2 = null;
if (entityTransaction.isActive())
entityTransaction.rollback();
em.clear();
em.close();
}
参考How to close a JPA EntityManger in web applications
+1每个答案的人帮助了我很多。我没有给出任何答案,因为我想为它发布完整的答案。谢谢