2013-08-09 7 views
1

많은 수의 이미지에 매우 빠르게 액세스해야하는 앱이 있으므로 어떤 방식 으로든 이미지를 메모리에로드해야합니다. 100MB 이상의 RAM을 사용하여 비트 맵을 사용했기 때문에 jpg 파일을 메모리로 읽어 바이트 어레이에 저장했습니다. 그런 다음 필자는 필 요할 때마다 디코드하여 캔버스에 씁니다. 이것은 메모리 제한을 존중하면서도 느린 디스크 접근을 차단하여 꽤 잘 작동합니다.byteArray에 이미지를 저장할 때 메모리 문제가 발생했습니다.

그러나 메모리 사용량은 나에게 '사용 안함'으로 보입니다. 나는 대략 33kb의 파일 크기를 가진 450의 jpgs를 저장하고있다. 이것은 약 15MB의 데이터를 합산합니다. 그러나 앱은 Eclipse DDMS와 Android (물리적 장치에서)가보고 한대로 35MB에서 40MB 사이의 RAM에서 계속 실행됩니다. 얼마나 많은 jpg가로드되고 응용 프로그램에서 사용하는 RAM을 jpg 당 약 60-70kb 줄이는 경향이 수정 시도, 각 이미지가 두 번 RAM에 저장되었음을 나타냅니다. 메모리 사용량은 실제 '누출'이 관여하지 않는다는 것을 의미하지 않습니다.

private byte[][] bitmapArray = new byte[totalFrames][]; 
for (int x=0; x<totalFrames; x++) { 
    File file = null; 
    if (cWidth <= cHeight){ 
      file = new File(directory + "/f"+x+".jpg"); 
    } else { 
      file = new File(directory + "/f"+x+"-land.jpg"); 
    } 
    bitmapArray[x] = getBytesFromFile(file); 
    imagesLoaded = x + 1; 
} 


public byte[] getBytesFromFile(File file) { 
    byte[] bytes = null; 
    try { 

     InputStream is = new FileInputStream(file); 
     long length = file.length(); 

     bytes = new byte[(int) length]; 

     int offset = 0; 
     int numRead = 0; 
     while (offset < bytes.length && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) { 
      offset += numRead; 
     } 

     if (offset < bytes.length) { 
      throw new IOException("Could not completely read file " + file.getName()); 
     } 

     is.close(); 
    } catch (IOException e) { 
        //TODO Write your catch method here 
    } 
    return bytes; 
} 

결국, 그들과 같이 화면에 기록 얻을 :

SurfaceHolder holder = getSurfaceHolder(); 
Canvas c = null; 
try { 
    c = holder.lockCanvas(); 
    if (c != null) {    
     int canvasWidth = c.getWidth(); 
     int canvasHeight = c.getHeight(); 
     Rect destinationRect = new Rect(); 
     destinationRect.set(0, 0, canvasWidth, canvasHeight); 
     c.drawBitmap(BitmapFactory.decodeByteArray(bitmapArray[bgcycle], 0, bitmapArray[bgcycle].length), null, destinationRect, null); 
    } 
} finally { 
    if (c != null) 
    holder.unlockCanvasAndPost(c); 
} 

내가 중복 여기에 무슨 어떤 종류의가 있다고 수정이 있습니까 여기

는 관련 로딩 코드? 아니면 jpgs를 byteArray에 저장하는 것과 관련된 많은 오버 헤드가 이처럼 있습니까?

답변

1

RAM에 바이트를 저장하는 것은 하드 드라이브에 데이터를 저장하는 것과 매우 다릅니다 ... 거기에 더 많은 오버 헤드가 있습니다. 바이트 배열 구조뿐만 아니라 객체에 대한 참조는 모두 추가 메모리를 차지합니다. 실제로 모든 추가 메모리에 대한 단일 소스는 없지만 일반적으로 RAM에 파일을로드하는 것보다 2 ~ 3 배는 더 많은 공간이 필요하다는 것을 기억하십시오 (경험상 볼 때, 여기서 어떤 문서도 인용 할 수는 없습니다).

이를 고려
File F = //Some file here (Less than 2 GB please) 
FileInputStream fIn = new FileInputStream(F); 
ByteArrayOutputStream bOut = new ByteArrayOutputStream(((int)F.length()) + 1); 

int r; 
byte[] buf = new byte[32 * 1000]; 

while((r = fIn.read(buf) != -1){ 
    bOut.write(buf, 0, r); 
} 

//Do a memory measurement at this point. You'll see your using nearly 3x the memory in RAM compared to the file. 
//If your actually gonna try this, remember to surround with try-catch and close the streams as appropriate. 

또한 그 사용되지 않는 메모리를 즉시 정리되지 않은 기억한다. getBytesFromFile() 메소드는 즉시 메모리 가비지 수집되지 않을 수있는 메모리 중복을 초래하는 바이트 배열의 복사본을 반환 할 수 있습니다. 당신이 안전하고 싶다면, getBytesFromFile (file)이 정리되어야 할 참조를 누설하고 있지 않은지 확인하십시오. 그것은 단지 당신이 그것을 한정된 횟수만큼 호출하기 때문에 메모리 누수로 나타나지 않을 것입니다.

+0

고맙습니다. 나는 그 생각을 고맙게 생각한다. getBytesFromFile을 살펴볼 것이다. 그러나 나는 다른 SO 대답에서 그것을 복사하고 아직 누출 참조를 감지하는 방법을 알고 충분히 경험하지 못합니다. 위의 질문에이 기능을 추가 했으므로 어떤 통찰력이라도 환영 할 것입니다. – Nicholas

+0

@Nicholas 위험스럽게 프로그래밍 된 InputStream (IOException에서 스트림을 닫지 않음)과 Integer.MAX_VALUE보다 큰 파일을 읽을 때 메서드가 실패한다는 사실 외에도 메소드는 괜찮습니다 (누출 된 참조 및 내용 없음). – initramfs

+0

감사합니다. 나는 그 문제를 해결하기 위해 내가 알아낼 수있는 것을 보게 될 것이다. – Nicholas

0

바이트 배열이 2 차원이므로 바이트 배열을 사용하여 이미지를로드하는 데 하나의 차원 만 필요할 수 있으며 두 번째 차원은 빈이지만 여전히 필요한 각 바이트에 필요한 RAM을 두 배로 늘릴 수 있습니다 당신이 사용하지 않는 기존 바이트

+0

그는 여러 이미지를 저장하기 때문에 2 차원입니다. – digitaljoel

+0

하지만 그는 그 중 하나의 차원만을 언급합니다 – Cob50nm

+0

저는 이번 주에 Java/Android 학습을 시작 했으므로 실수 일 수 있습니다. 제 이해는 두 번째 차원이 이미지의 각 바이트를 별도의 배열 '셀'에 저장하는 데 사용된다는 것입니다. 원래 다양한 배열 데이터 유형을 사용하여 하나의 차원으로 시도했지만 작동하지 못했습니다. – Nicholas

관련 문제