2012-05-28 4 views
1

구체적으로 어떻게 처리해야할지 모르겠습니까? 기본적으로 나는 내 기억을 넘어 많은 데이터를 생성하는 프로그램을 가지고있다. (예를 들어, 10 기가의 데이터와 4 기가의 램이있다.) 나는 데이터를 가져 와서 디스크에 쓰는 쓰레드를 포크하기로 결정했다. 비록 디스크 쓰기가 그것을 생성하는 프로세스를 따라 잡을 수 없다는 것을 알았지 만, 애플리케이션을 디스크에 얼마나 빨리 쓸 수 있을지를 바랄 수 있었다. 하지만 잠시 후에 나는 힙 메모리 부족 오류가 발생합니다. 내가 생각대기열에 저장된 큰 데이터를 파일에 쓰는 중 메모리 오류가 발생했습니다.

다음

의 부품과 관련된 :

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"); 
     } 
    } 

아니에요 : 여기

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

이 파일에 저장하는 부분 : 모든 데이터가이 변수에 넣어 쓸 수있다 내가 뭘 잘못하고 있는지, 내 프로세스가 그것에 쓰는 것을 멈추게하기 위해 결과의 큐를 특정 크기로 차단해야합니까? 또는 파일을 쓰는 중 뭔가 잘못하고 있는데, 버퍼링되지 않은 버전을 표시하고 있지만 동일한 결과가있는 bufferedWriter를 시도 했습니까? 프로그램이 실행되는 동안 파일 크기가 0 인 것을 볼 수 있습니다. 한 번만 충돌하면 쓰기가되는 것처럼 보입니다.이 문제는 bufferedWriter 없이도 메모리에서 유지되며 메모리 문제를 일으킬 수 있습니까?

내 아이디어는 SaveToFile 스레드가 대기열을 지우면 다른 프로세스가 계속 쓰기 위해 여유 공간을 확보한다는 것입니다 (이것들은 주 프로그램과 SaveToFile을 실행하는 유일한 스레드입니다).

답변

1

결과의 대기열을 특정 크기로 차단해야 프로세스가 처리를 중지하지 않습니까?

예. 작성자가 기록 할 수있는 것보다 빠르게 데이터를 생성하면 프로세스가 메모리를 모두 소모 할 가능성이 가장 높습니다.

다른 문제는 LinkedList이 동기화되지 않으므로 LinkedList을 사용하여 스레드간에 데이터를 전달할 때 잠금을 사용해야합니다.

용량을 제한하려면 ArrayBlockingQueue 또는 LinkedBlockingQueue을 사용할 수 있습니다. 추가 보너스로 두 가지 모두 스레드로부터 안전하므로 외부 동기화가 필요하지 않습니다.

마지막으로, 코드가 I/O 바인딩 인 경우 두 스레드로 분할하면 비교적 적은 이점을 얻을 수 있습니다. 이 모든 추가 복잡성을 거의 또는 전혀 도움이되지 않을 정도로 도입 할 수 있으므로 이는 가치가 있습니다.

+0

메모리가 가득 차면 같은 효과가있을 것이라고 생각했습니다. 더 많은 공간이 생길 때까지 쓰는 것을 멈출 수 있습니까? –

+0

@ Error_404 : 아니, 그렇게하지 않습니다. – NPE

+0

고마워, 나는 LinkedList..sorry를 차단하고 동기화하는 방법을 배우게 될 것이다. 그러나 고통을 느끼는 것은 왜 잠금이 필요한가?내가 목록의 끝 (result.add (data ...);)을 작성하고 앞에서 폴링하면 잠금의 이점은 무엇입니까? –

1

이미 언급했듯이 디스크 작성자는 메모리 작성자보다 느립니다. 그러므로, 나는 당신이 결코 플러시 부분에 도달하지 않을 것이라고 믿습니다. 왜냐하면 결과는 결코 비어 있지 않기 때문입니다.

나는 그 안에 큐가 들어있는 클래스를 만들고 최대 큐 크기를 설정하는 것이 가장 좋은 방법이라고 생각한다. 그래서, 만약에 메모리얼 작가가 뭔가를 대기열에 넣으려고한다면 그것은 막힐 것입니다.

대기열 메소드가 대기 중임을 나타내지는 않지만 대기열 해제 메소드에서 온 신호를 기다리면서 대기 상태에 빠져있을 것을 제안합니다.

관련 문제