【问题标题】:My Java app running out of memory我的 Java 应用程序内存不足
【发布时间】:2016-03-18 04:26:34
【问题描述】:

我的应用程序在执行包含大量数据的操作时内存不足。数据是一个 Java 列表,大小约为 100K 元素。 PersistData 是实现操作的类,PersistDataIntoDB 是执行实际操作的类。由于操作耗时,PersistData 的调用者会收到一个响应,说明操作已启动,并且有额外的 API 可以获取操作的状态。

另外,整个操作是并发的,并且操作有多个调用者。

这是代码的样子(我希望它可读)。

public class PersistData {
    public Boolean persistData(List<ClassA> dataRecs) {
        //some checks (smaller operation)
        persistDataInDifferentThread(dataRecs);
        //if no errors in checks return true
        return true;
    }

    private void persistDataInDifferentThread(List<ClassA> dataRecs) {
        Thread runnerThread = new Thread(new Runnable() {
            public void run() {
                try {
                    List convertedList = constructClassBUsingClassA(dataRecs);
                    PersistDataIntoDB dbPersist = new PersistDataIntoDB();
                    dbPersist.persistDataInDB(convertedList);
                }
                catch (Exception e) {
                }
            }
        });
    }

     private List<ClassB> constructClassBUsingClassA(List<ClassA> dataRecs) {
    List<ClassB> tempList = new ArrayList<ClassB>();
    for (int i = 0; i < dataRecs.size(); i++) {
        ClassA tempRec = dataRecs.get(i);
        ClassB tempRecB = new ClassB();
        //put stuff from tempRec to tempRecB
        tempList.add(tempRecB);
    }
    return tempList;
}

}

执行持久性的类。

public class PersistDataIntoDB {
     public Boolean persistDataInDB(List<ClassB> dataRecs){
        //if all goes well return true
        return true;
    }
}

我的问题是我的方法persistDataInDifferentThread 是否可以重构?因为在它运行时,内存中有两个大列表,并且对persistDataInDB 的调用需要很长时间才能完成,并且垃圾收集器可能不会卸载List&lt;ClassA&gt; 尽管我在调用persistDataInDB 后不需要它。

我上面的分析错了吗?我只需要增加最大堆,因为我正在处理大数据?

【问题讨论】:

  • 很难从您提供的内容中分辨出来,当前实现的一个明显问题是重复调用persistData 将启动的线程数没有限制。足够频繁地调用它,您很容易耗尽资源。您可能需要考虑使用队列和消费者或线程池方法。
  • 您能否展示您如何设置列表/列表中的内容。
  • 您确定需要为每个列表创建 PersistDataIntoDB dbPersist 吗?看起来这是一个带有静态方法的类。
  • @Jan 列表包含我的数据结构之一的元素。数据结构 ClassA 与 ClassB 略有不同,因此,我为 ClassA 的每个对象构造 ClassB 的对象,这是调用者提供的列表。
  • 你能展示一下constructClassBUsingClassA的完整代码吗?不清楚如何将一个类转换为另一类?

标签: java performance memory-management


【解决方案1】:

我上面的分析错了吗?我只需要增加最大堆,因为我正在处理大数据?

是的,是的。

1) 使用多个线程不会增加或减少使用的堆空间量。

2) 如果堆满了,那么 JVM 会在抛出 OOME 之前尽一切努力回收空间。

唯一可能会有所不同的是,如果一个线程创建列表并将其传递给第二个实例以进行持久化......并且还挂起对列表的引用。这可能会导致列表保持可访问的时间超过其需要的时间。

我想如果您有多个运行器线程持久保存多个列表,并且工作到达的速度比您处理它的速度快,那么您也可能会遇到麻烦。如果这是问题所在,那么您需要采取一些措施来控制您接受请求的速度。

【讨论】:

  • 谢谢。我还没有确认“挂在对列表的引用”部分
  • 我的理解是@dbPersist.persistDataInDB(convertedList);,两个列表(ClassA和ClassB的列表)在内存中。但是我不需要 ClassB 的列表,因为我已经处理过了。对吗?
  • @dRV 持久化列表将在persistDataInDifferentThread 完成后从内存中删除,因为应用程序丢失了指向该列表的链接。
  • 一旦创建了 ClassB 列表,就没有任何需要来保留对 ClassA 列表的引用。 (如果你这样做了,那么你将增加堆使用量......但解决方案是“不要”。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-19
  • 2012-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多