我不确定如何专门处理这个问题(Java新手)。基本上我有一个程序可以生成大量超出我记忆的数据(例如,它的10个演出数据,我有4个演出的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)。
答案 0 :(得分:1)
我是否需要以特定大小阻止结果的队列,以便我的进程停止写入它?
是的,你这样做。生成数据的速度快于生成数据的生产者最有可能导致进程耗尽内存。
另一个问题是LinkedList
未同步,因此在使用LinkedList
在线程之间传递数据时需要使用锁定。
要限制容量,您可以使用ArrayBlockingQueue
或LinkedBlockingQueue
。作为额外的好处,两者都是线程安全的,因此不需要外部同步。
最后,如果您的代码是I / O绑定的,就像它看起来那样,将它分成两个线程可能会获得相对较少的好处。值得注意的是,因为你可能会引入所有这些额外的复杂性而几乎没有任何好处。
答案 1 :(得分:1)
正如您已经说过的,您的磁盘写入器比您的记忆编写器慢。因此,我相信你永远不会进入冲洗部分,因为结果永远不会是空的。
我认为最好的方法是创建一个包含队列中的队列并建立最大队列大小的类。因此,如果记忆编写者试图将某些内容排入队列,那么它将被阻止。
我建议您的队列方法不会忙于等待,但是会等待来自您的出队方法的信号。