2013-05-30 1 views
1

일부 시스템 간의 상호 작용을 위해 GZIP 압축을 구현하고 있습니다. 이 시스템은 Java와 C#으로 작성되었으므로 GZIP 스트림은 표준 라이브러리를 지원하므로 양쪽에서 사용되었습니다.힙 오버플로없이 큰 (압축되지 않은 70MB) 바이트 스트림의 압축을 어떻게 처리해야합니까?

C# 측에서 모든 것이 가장 큰 테스트 파일 (압축되지 않은 70MB)까지 작동하지만 힙 공간이 부족한 Java 문제가 발생합니다. 힙 크기를 IDE의 용량으로 늘려 보았지만 문제는 해결되지 않았습니다.

Java 코드를 시도하고 최적화하기위한 몇 가지 조치를 취했지만 데이터가 힙에 겹치지 않도록하는 방법은 없습니다. 이것을 처리 할 수있는 좋은 방법이 있습니까? 아래는 현재 (작은 스트림 작업) 솔루션의 하위 집합입니다.

편집 : @MarkoTopolnik의 권장 사항에 따라 수정 된 코드. 변경 사항으로 충돌 전 1700 만자를 읽습니다.

public static String decompress(byte[] compressed, int size) 
{ 
    GZIPInputStream decompresser; 
    BufferedReader reader; 
    char buf[] = new char[(size < 2048) ? size : 2048]; 
    Writer ret = new StringWriter(buf.length); 

    decompresser = new GZIPInputStream(new ByteArrayInputStream(compressed), buf.length); 
    reader = new BufferedReader(new InputStreamReader(decompresser, "UTF-8")); 

    int charsRead; 
    while((charsRead = reader.read(buf, 0, buf.length)) != -1) 
    { 
     ret.write(buf, 0, charsRead); 
    } 
    decompresser.close(); 
    reader.close(); 

    return ret.toString(); 
} 

코드는 ArrayList에서 760 만 개 문자 위에 작은 타격 후 다이와 스택 트레이스는 ArrayList.add() 호출 원인임을 나타낸다 (확장되는 내부 어레이를 트리거링 후 실패).

위에서 편집 한 코드를 사용하면 AbstractStringBuilder.expandCapacity()을 호출하면 프로그램이 종료됩니다.

동적 배열을 구현하는 데 메모리가 덜 비싼 방법이 있습니까? 아니면 압축 해제 된 스트림에서 String을 가져 오기 위해 사용할 수있는 완전히 다른 접근 방식이 있습니까? 어떤 제안이라도 대단히 감사하겠습니다!

답변

2

나는 전체를 메모리로 읽어들이는 대신에 chunk를 사용했다. 한 번에 1024 바이트 버퍼를 읽고 곧바로 2 단계 읽기/쓰기 프로세스보다 유닉스 파이프처럼 쓰는 것이 좋다.

+1

기존의 프레임 워크 제약으로 인해 옵션이 아닌 경우가 많습니다. 나는 OP에 그런 사건이 있다고 말하고 싶다. –

+0

예, 이전 프레임 워크로 구현할 방법이 없습니다. 함수는 String을 반환해야하며 주어진 바이트 배열을 압축해야합니다. 이러한 제약 조건을 통해 솔루션을 구현할 수있는 방법을 발견 할 수 있습니다. – Dan

+0

당신 말이 맞아요. 모든 플러그인이 설치된 VisualVM을 사용하여 메모리가 소비되는 곳을 확인하는 것이 좋습니다. 프레임 워크를 버릴 때가 왔습니다. – duffymo

2

오 예, 훨씬 효율적인 방법이 있습니다. 코드에서 가장 눈에 띄지 않는 비효율은 ArrayList<Character>을 만드는 것입니다. 즉, 각 문자는 약 30 바이트의 메모리를 차지합니다. 7.6 백만을 곱하면 250MB입니다.

사용해야하는 것은 StringWriter과 그 방법이 write(char[],int,int)이며 이미 가지고있는 것과 동일한 버퍼로 호출 할 수 있습니다. 이것은 약 25 배나 더 많은 메모리 효율이 될 것입니다.

+0

고마워요! 힙이 초과되기 전에 1 천만 개 이상의 문자를 받았습니다. 완전히 문제를 해결하지는 않지만 좋은 출발점입니다. – Dan

+0

그것은 놀랍게도 거의 없습니다. 필자는'Character' 캐싱을 설명하지 않았기 때문에 그런 것 같아요. –

관련 문제