【问题标题】:Memory error while writing large queued data to file将大型排队数据写入文件时出现内存错误
【发布时间】:2012-05-28 16:27:53
【问题描述】:

我不确定如何具体处理这个问题(Java 新手)。基本上我有一个程序可以生成大量超出我记忆的数据(例如,它的 10 gigs 数据和我有 4 gigs 的 ram)。我决定派生一个线程来获取数据并将其写入磁盘,尽管我知道磁盘写入永远跟不上生成它的进程,但我希望我的应用程序可以绑定到我写入磁盘的速度。但过了一会儿,我得到了堆内存不足的错误。

以下是我认为相关的部分: 所有要写入的数据都放在这个变量中:

private static Queue<short[]> result =  new LinkedList <short[]> ();

这是保存到文件的部分:

   static class SaveToFile extends Thread {


        public void run() {
                FileWriter bw = null;
                try {
                    bw = new FileWriter("output.csv");
                    Thread.sleep(500); //delay the start so the queue can have some data
                } catch (IOException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            System.out.println("size of results during execution is " + result.size());
            while(!result.isEmpty()) {
                short[] current = result.poll();
                try {
                    bw.write(Arrays.toString(current) + "," + "\n");
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            try {
                bw.flush();
                bw.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println("file writing is done");
        }
    }

我不确定我做错了什么,我是否需要以一定的大小阻止结果队列,以便我的进程停止写入它?还是我在写入文件时做错了什么,我显示的是非缓冲版本,但我尝试过 bufferedWriter 得到相同的结果?我观察到,当程序运行时,文件大小为 0,只有当它崩溃时,它才似乎在写入。即使没有 bufferedWriter,它是否将它保存在内存中,这是否会导致内存问题?

我的想法是,当 SaveToFile 线程清除队列时,它为其他进程继续写入它腾出更多空间(这些是我正在运行的唯一线程,主程序和 SaveToFile)。

【问题讨论】:

    标签: java io queue


    【解决方案1】:

    我是否需要以一定的大小阻止结果队列,以便我的进程停止写入?

    是的,你知道。生产者生成数据的速度快于写入速度是您的进程内存不足的最可能原因。

    另一个问题是LinkedList不同步,所以在使用LinkedList在线程之间传递数据时需要使用锁定。

    要限制容量,您可以使用ArrayBlockingQueueLinkedBlockingQueue。另外,两者都是线程安全的,因此不需要外部同步。

    最后,如果您的代码是 I/O 绑定的(看起来是这样),那么将其拆分为两个线程的好处可能相对较小。这一点值得牢记,因为您可能会引入所有这些额外的复杂性而几乎没有好处。

    【讨论】:

    • 我想如果内存满了也会有同样的效果?它会停止写入,直到有更多空间?
    • @Error_404:不,它不会那样做。
    • 好的,谢谢,我将学习如何阻止和同步 LinkedList ..对不起,这很痛苦,但为什么我需要锁定?如果我写到列表的末尾(result.add(data...);) 并从前面轮询,锁定有什么好处?
    • @Error_404:Javadoc 说明了一切:请注意,此实现不同步。如果多个线程同时访问一个链表,并且至少有一个线程在结构上修改了链表,则它必须在外部同步。
    • 谢谢 aix。有道理..我会更多地研究并实施它。非常感谢您的帮助和建议!
    【解决方案2】:

    正如你已经说过的,你的磁盘写入器比你的内存写入器慢。因此,我相信你永远不会到达冲洗部分,因为结果永远不会是空的。

    我相信最好的方法是创建一个包含队列的类并建立最大队列大小。因此,如果 memorywriter 试图将某些内容排入队列,它将被阻止。

    我建议您的队列方法不要忙于等待,而是进入睡眠状态等待来自您的出队方法的信号。

    【讨论】:

      猜你喜欢
      • 2018-11-08
      • 2016-10-09
      • 1970-01-01
      • 2019-04-29
      • 2020-03-19
      • 1970-01-01
      • 2019-08-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多