【问题标题】:How to resolve java.lang.OutOfMemoryError error by "java.lang.String", loaded by "<system class loader>" Eclipse Memory Analyzer如何解决由“<system class loader>”加载的“java.lang.String”的 java.lang.OutOfMemoryError 错误 Eclipse Memory Analyzer
【发布时间】:2013-07-09 07:41:15
【问题描述】:

我正在读取一些大型 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)

使用内存分析器,我创建了 .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();
        }
    }

【问题讨论】:

  • 你如何读取这些 XML 文件?
  • 您是否可以用 StringBuilder 替换所有字符串(在读取这些 XML 文件时)?如果是,那么你得到了解决方案
  • @freak 这并没有真正的帮助,因为一个 800M 大小的 XML 文件将占用至少 1.6G 的内存(每个字符 2 个字节)而不计算任何开销。甚至StringBuilder 也会在它的边界。
  • @freak,Uwe Plonus,The New Idiot 可以做什么,因为我已经将我的 jvm 或 jre 内存增加到 2048 M??
  • @Shiv 你不会做一些事情,比如把你解析的所有东西都放在一张地图中以供后续处理吗?你能显示一些代码吗?

标签: java string memory-leaks heap-memory heap-dump


【解决方案1】:

如果你正在使用,请不要使用String。用StringBufferStringBuilder替换它。另外,尝试增加内存。我猜2048是可以的,但如果问题仍然存在,则将其更改为4096m甚至可以尝试 6000m

【讨论】:

    【解决方案2】:

    终于解决了我的问题。 以下事情有所帮助:

    1.堆大小2048就够了。

    2. 另一个问题是我使用的是 String。

    并且字符串对象是不可变的

    不可变是指存储在 String 对象中的值不能更改。然后我们想到的下一个问题是“如果 String 是不可变的,那么我如何能够随时更改对象的内容?” .好吧,准确地说,反映您所做更改的不是同一个 String 对象。在内部创建了一个新的 String 对象来进行更改。

    参考Difference between string and stringbuffer, Stringbuilder

    所以我删除了 JPA 实体以外的实体的 getter 和 setter。并将所有数据直接插入数据库而不将它们设置为任何对象。

    3.第三个也是主要问题是JPAEntityManager

    我的代码没有确保 EntityManager 在方法完成时始终关闭。 就业务逻辑中发生 RuntimeException 而言,em EntityManager 保持打开状态!

    所以总是关闭它,你也可以在 finally 块中将你的对象设置为空

    finally {
                        Obj1 = null;
                        Obj2 = null;
                        if (entityTransaction.isActive())
                            entityTransaction.rollback();
                        em.clear();
                        em.close();
    
                    }
    

    参考How to close a JPA EntityManger in web applications

    +1 为每个 Answer 伙计,这对我帮助很大。我没有标记任何答案,因为我想发布完整的答案。谢谢

    【讨论】:

      【解决方案3】:

      看起来您在发布代码之前对其进行了编辑,或者发布了不完全正确的代码。请改正。

      首先,您的代码不会编译。

      其次,在save函数中不传递Reader。在process(StructuredNode node) 中创建并填写Entity,并传递Entity,而不是Reader,来保存函数。

      第三,正确处理save函数中的异常。如果发生异常,回滚事务。

      【讨论】:

      • 是的,先生,我已经完全按照您的说法完成了 obj 是实体类的对象。我首先设置实体并传​​递它以保存我为idea编辑过的代码
      【解决方案4】:

      尝试使用另一个解析器进行 XML 处理。

      使用例如处理一个 800M 的大 XML 文件。 DOM 不可行,因为它占用了很多内存。

      尝试在 Java 中使用 SAXStAX 并立即处理解析结果,而无需尝试将完整的 XML 文件加载到内存中。

      并且也不要将解析结果保存在内存中。尽快将它们写入数据库,并尽可能缩小解析结果的范围。

      也许使用数据库中的中间表,并对数据库内的所有数据集进行处理。

      【讨论】:

      • @TheNewIdiot - 他甚至从未说过他在使用DOM——你怎么知道这是正确的答案?
      • @DaoWen 我没有说正确的答案,我说的是正确的建议
      • 这正是解决方案。使用 SAX 对其进行解析,随时将记录提交到数据库(或者以 100 个为一组),并且在不需要时不要将整个该死的文件一次保存在内存中。
      • @DaoWen DOM 是我的一个假设,因此改变了答案。关键点在下一段:不要一次加载完整的 XML 文件。
      • @UwePlonus - 他甚至从未提到过解析——他可能只是将文件作为字符串读取,然后将其转储到数据库中。但是,这似乎是最好的建议,因为您可以流式传输 输入,而不是将其全部放入内存中。 (基于“StringBuffer 有帮助吗?”评论我认为他没有使用解析器。)
      【解决方案5】:

      我的主要提示:再次检查您的 JPA 代码。应尽可能隔离。

      一个想法是使用带有注释的 JAXB。 IdentityHashMap(键使用==而不是equals)是一种罕见的东西,可能是JPA,可能是XML标签?您还可以查看使用了哪个 XML 解析器(检查工厂类,或通过 java SPI、服务提供者接口列出所有 XML 解析器提供者)。

      您可以共享字符串,例如长度小于 20 的所有字符串。使用 Map&lt;String, String&gt;

      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 流)。

      【讨论】:

        【解决方案6】:
        1. 最明显的答案是增加 JVM 内存,正如这里已经提到的,使用 java -XmxNN
        2. 使用SAXParser 而不是DOM 树(如果您还没有这样做的话)。这取决于您的应用程序设计,因此您必须对其进行研究,看看这是否可行。
        3. 检查您的代码并尝试删除所有不需要的对象,以便将它们从 GB 中删除。这可以包括,即在循环内移动变量而不是将它们放在循环之外,以便尽早删除引用。在您不再需要它们后将未使用的元素设置为 null

        在不了解您的代码的情况下,这只是一般指导方针。

        【讨论】:

        • 可能的。取决于您如何访问它。使用字符串缓冲区,您至少可以传递相同的对象,因此您可能会创建较少的引用。字符串的问题在于它们是不可变的,在这方面 StringBuffer 确实可以提供帮助。
        【解决方案7】:

        您可以在启动 Java 时增加堆大小:

        java -Xmx8G
        

        【讨论】:

        • @TheNewIdiot - 实际上,如果他的默认堆大小太小,那么这个正确的答案,它保证只要工作他选择了一个足够大的堆大小。您的评论在回复“哦,我的磁盘空间不足 - 我应该购买第二个硬盘驱动器”时同样没有意义。这只是一个临时修复——我可能会再次用完空间......
        • 他读取的文件不必局限于他拥有的RAM大小,甚至我们不知道他是否负担得起8G。
        • @DaoWen 在解析一个800M的XML文件时,它可能会变得更大,他会再次遇到同样的问题。
        • @UwePlonus - 我同意您可以流式传输数据的解决方案会更加优雅 - 但它可能还需要他重组大量代码。如果他现在可以通过投入更多 RAM 来解决此问题,然后花时间重新构建它,那么投入更多 RAM 可能是个好主意。
        【解决方案8】:

        你的堆没有限制,不能在内存中保存这么大的 xml。尝试使用 -Xmx JRE 选项增加堆大小。

        尝试使用http://vtd-xml.sourceforge.net/ 来更快、更轻松地处理 xml。

        【讨论】:

          猜你喜欢
          • 2016-06-26
          • 1970-01-01
          • 1970-01-01
          • 2018-06-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多