2013-06-03 3 views
1

큰 텍스트 파일 (약 5 메가 바이트)을 읽어야합니다.무거운 텍스트 파일 읽기

BufferedReader()을 사용하여이 파일을 읽었을 때 메모리 누수 및 힙이 발생합니다. 내 코드를 최적화 할 수있는 대체 옵션이 있습니까?

  StringBuffer sb = new StringBuffer(); 
      BufferedReader reader = new BufferedReader(new FileReader(vCache)); 
      String line = null; 

      while ((line = reader.readLine()) != null) 
      { 
       sb.append(line); 
      } 
+0

로그가 비싸고 (문자열이 일치 함) 메모리 누출이 ... – Johannes

+0

왜 5MB 파일을 읽습니까? 이것에 대한 요구 사항을 설명해주십시오. – krishnakumarp

+0

@krishnakumarp 글쎄, 필자는 모든 웹 서버 데이터베이스 행을 가져와 텍스트 파일에 저장하고 json 형식으로 파싱 한 다음 마지막으로 로컬 데이터베이스에 하나씩 삽입해야합니다. – iSun

답변

0

JSON을 구문 분석하고 있습니다.

당신이 거기에 있다면 prettifying (예 : 들여 쓰기, 개행 등)을 제거하여 입력 파일을 작게 만들 수 있습니다.

스트림에서 직접 읽는 구문 분석기를 사용해 볼 수도 있습니다. 한 번에 모든 것을 버퍼링하지 않아도됩니다. 예를 들어 Android는 JsonReader을 제공하므로 스트림을 파싱하고 직접 데이터 구조를 제어 할 수 있습니다. 따라서 더 많은 메모리 효율적인 구조를 사용할 수 있으며 전체 스트림을 버퍼링하지 않습니다. API 레벨 11에서 추가되었으므로 이전 버전과의 호환성이 문제가 될 수 있습니다.

최상위 수준 개체가 배열 인 경우 하나의 대안으로 배열을 여러 개의 작은 배열로 분할하거나 다른 파일로 분할하여 개별적으로 구문 분석하고 하위 배열을 병합 할 수 있습니다. 기본 오브젝트가 유사한 구조를 갖는 경우, 병합 전에이를 Java 오브젝트로 변환 할 수 있으며, 이는보다 컴팩트 한 메모리 구조를 갖습니다.

+0

블라드 감사합니다, 예, 나는 json을 파싱하려고합니다. 스트림에서 json을 읽는 것에 대한 예를 들어 주시겠습니까? – iSun

+0

Jackson JSON Parser (http://wiki.fasterxml.com/JacksonHome)를 사용해보십시오. 직접 inputStream에서 JSON을 파싱 할 수 있습니다. – reidzeibel

1

하는 시도 난 당신이 로컬 파일을 읽고 같은데요 InputStream 대신

try { 
    InputStream is = new FileInputStream(vCache); 
    byte[] b = new byte[is.available()]; 
    is.read(b); 
    String text = new String(b); 
} 
1

BufferedReader의 사용.

InputStream is = new FileInputStream(vCache); 
byte[] buffer = new byte[is.available()]; 
is.read(buffer); 
is.close(); 
jsonContent = new String(buffer, "UTF-8"); 

하는 것은 여전히 ​​메모리에 안드로이드와 같은 큰 파일을 읽고 문제를 초대 할 수있다 그러나이 경우, 당신은 바이트 배열에 전체 파일을 읽고 다음 문자열로 변환 더 나을 수 있습니다. 5MB json 파일을 읽어야 할 경우 응용 프로그램을 올바르게 구성하지 못했을 것입니다.

1

BufferedRedaer에 의해 사용되는 bufferSize은입니다.하지만 한 줄씩 읽는 중일 때마다 누적 될 것입니다. 이 문제를 개선하기 위해 다음을 사용할 수 있습니다

BufferedReader(Reader in, int sz) < - 작은 값으로 sz을 사용한다고 말할 4KB

read(char[] cbuf) < - 제약 조건을 cbuf 크기를

close() < 독자 크기의로 - 메모리가 만들었 었지 된 어떤 판독기 인스턴스별로 이제 GC 수 있습니다

이제 코드 StringBuffer sb은 전체 파일 내용과 마찬가지로 모든 행을 포함합니다. 위의 변경 후 필요한 메모리 (~ fileSize)를 JVM에 사용할 수 없으면 OOM 문제가 다시 발생합니다. 그럴 지 모르겠다면, 위의 경우를 제외하고는 로컬 메모리 스파이크를 약간 개선해야합니다.

0

귀하의 코드는 ... 행을 읽고 StringBuilder에 누적합니다. 선을 누적한다는 단순한 사실은 메모리 누수의 한 형태입니다.즉

BufferedReader reader = new BufferedReader(new FileReader(vCache)); 
    String line = null; 
    while ((line = reader.readLine()) != null) { 
     process(line); 
    } 

, 메모리에 라인을 축적하지 마십시오 :

그 누출을 방지하는 가장 좋은 방법은 다음과 같이 작동하도록 응용 프로그램을 변경하는 것입니다. 읽은 내용을 처리 한 다음 폐기하십시오.

StringBuilder sb = new StringBuilder(fileSizeInCharacters); 

을 피할 :이 같은 StringBuilder를 할당하는 경우


하여 처리하면에있는 그런 경우

메모리에서 라인을 축적, 당신은 더 나은 메모리 사용량을 얻을 것이다 재 할당이 필요하며, 최악의 경우 파일 크기의 3 배의 문자가 필요합니다 (문자 수).

그러나 조만간 같은 문제가 발생할 것입니다. 메모리의 파일 내용을 축적하는 것은 확장되지 않습니다.


귀하의 의견은 이것이 실제로 JSON 처리 문제임을 나타냅니다.

스트리밍 API의 아이디어는 당신이 인 -로 JSON "개체"를 변환 할 필요가 없다는 것입니다 : 여기 Q & A는 스트리밍 JSON 처리의 주제이다 모든 것을 나타내는 메모리 트리 구조.

0

각 줄이 하나의 완전한 db 행과 잘 형성된 json에 해당하도록 JSON을 보냅니다. 이렇게하면 전체 파일을 함께 처리 할 필요가 없습니다.

//StringBuffer sb = new StringBuffer(); 
BufferedReader reader = new BufferedReader(new FileReader(vCache)); 
String line = null; 

while ((line = reader.readLine()) != null) { 
    //Parse JSON 
    //Insert into local SQLite DB. 
}