1

我不确定如何具体处理这个(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)。

4

2 回答 2

1

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

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

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

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

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

于 2012-05-28T16:29:32.570 回答
1

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

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

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

于 2012-05-28T16:35:38.643 回答