저는 안드로이드 플랫폼의 이상한 동작, 즉 비트 맵/자바 힙 메모리 한계로 고심하고 있습니다. 장치에 따라 Android는 앱 개발자를 16, 24 또는 32 MiB의 Java 힙 공간으로 제한합니다 (또는 뿌리를 휴대 전화에서 임의의 값을 찾을 수도 있음). 나는 다음과 같은 API의와 사용을 측정 할 수있는 이것은 틀림없이 매우 작지만 상대적으로 간단하다 : 충분히안드로이드 비트 맵 한도 - java.lang.OutOfMemory 예방
Runtime rt = Runtime.getRuntime();
long javaBytes = rt.totalMemory() - rt.freeMemory();
long javaLimit = rt.maxMemory();
쉬운; 지금 비틀어졌다. 안드로이드에서 비트 맵은 거의 예외없이 네이티브 힙에 저장되며 Java 힙에 포함되지 않습니다. 구글의 일부 순수하고 눈에 거슬리는 순수 개발자는 "이것이 나쁘다"고 판단하고 개발자가 "공정한 몫보다 더 많이"얻을 수 있도록 결정했다. 그래서 비트 맵과 다른 리소스에 의해 발생하는 네이티브 메모리 사용량을 계산하는 멋진 코드 조각이 있습니다. 그리고 Java 힙과 합계해서 ..... java.lang.OutOfMemory로 가면됩니다. 우 흐
큰 문제는 없습니다. 나는 많은 비트 맵을 가지고 있으며 항상 모든 것을 필요로하지는 않는다. 나는 지금 사용되지 않는 것들을 "페이지 아웃"할 수 있습니다 :
그래서 try/catch를 사용하여 모든 비트 맵로드를 래핑 할 수 있도록 코드를 리팩토링했습니다 :
~ 26 freeMemory에서 만 4.7 MiB 크기이지만,와 - 어떻게 totalMemoryE/Epic (23221): OUT_OF_MEMORY (caught java.lang.OutOfMemory) I/Epic (23221): ArchPlatform[android].logStats() - I/Epic (23221): LoadedClassCount=0.00M I/Epic (23221): GlobalAllocSize=0.00M I/Epic (23221): GlobalFreedSize=0.02M I/Epic (23221): GlobalExternalAllocSize=0.00M I/Epic (23221): GlobalExternalFreedSize=0.00M I/Epic (23221): EpicPixels=26.6M (this is 4 * #pixels in all loaded bitmaps) I/Epic (23221): NativeHeapSize=29.4M I/Epic (23221): NativeHeapAllocSize=25.2M I/Epic (23221): ThreadAllocSize=0.00M I/Epic (23221): totalMemory()=9.1M I/Epic (23221): maxMemory()=32.0M I/Epic (23221): freeMemory()=4.4M W/Epic (23221): Recycling bitmap 'game_word_puzzle_11_aniframe_005' I/Epic (23221): BITMAP_RECYCLING: recycled 1 bitmaps worth 1.1M). age=294
참고 :
while(true) { try { return BitmapFactory.decodeResource(context.getResources(), android_id, bitmapFactoryOptions); } catch (java.lang.OutOfMemory e) { // Do some logging // Now free some space (the code below is a simplified version of the real thing) Bitmap victim = selectVictim(); victim.recycle(); System.gc(); // REQUIRED; else, weird behavior ensues } }
참조, 여기에 좋은 작은 로그 미리보기가 예외를 잡기 내 코드를 보여, 일부 비트 맵을 재활용입니까? 비트 맵으로 채워진 기본 메모리의 MiB는 우리가 제한에 도달 한 31/32 MiB 범위에 있습니다. 모든로드 된 비트 맵에 대한 실행 기록이 26.6 MiB이지만 기본 할당 크기는 25.2 MiB이므로 여기서 약간 혼란 스럽습니다. 그래서 나는 잘못된 것을 세고있다. 그러나 그것은 모두 야구장에 있으며, mem-limit으로 일어나는 크로스 풀 "합계"를 분명히 보여줍니다.
나는 그것을 고쳐야한다고 생각했다. 하지만, 안드로이드는
여기 내가 네 테스트 장치의 두에서 무엇을 얻을 ... 그렇게 쉽게 포기하지 않을 것이다 : 기본 충돌의I/dalvikvm-heap(17641): Clamp target GC heap from 32.687MB to 32.000MB D/dalvikvm(17641): GC_FOR_MALLOC freed <1K, 41% free 4684K/7815K, external 24443K/24443K, paused 24ms D/dalvikvm(17641): GC_EXTERNAL_ALLOC freed <1K, 41% free 4684K/7815K, external 24443K/24443K, paused 29ms E/dalvikvm-heap(17641): 1111200-byte external allocation too large for this process. E/dalvikvm(17641): Out of memory: Heap Size=7815KB, Allocated=4684KB, Bitmap Size=24443KB, Limit=32768KB E/dalvikvm(17641): Trim info: Footprint=7815KB, Allowed Footprint=7815KB, Trimmed=880KB E/GraphicsJNI(17641): VM won't let us allocate 1111200 bytes I/dalvikvm-heap(17641): Clamp target GC heap from 32.686MB to 32.000MB D/dalvikvm(17641): GC_FOR_MALLOC freed <1K, 41% free 4684K/7815K, external 24443K/24443K, paused 17ms I/DEBUG (1505): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** I/DEBUG (1505): Build fingerprint: 'verizon_wwe/htc_mecha/mecha:2.3.4/GRJ22/98797:user/release-keys' I/DEBUG (1505): pid: 17641, tid: 17641 I/DEBUG (1505): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000000 I/DEBUG (1505): r0 0055dab8 r1 00000000 r2 00000000 r3 0055dadc I/DEBUG (1505): r4 0055dab8 r5 00000000 r6 00000000 r7 00000000 I/DEBUG (1505): r8 000002b7 r9 00000000 10 00000000 fp 00000384 I/DEBUG (1505): ip 0055dab8 sp befdb0c0 lr 00000000 pc ab14f11c cpsr 60000010 I/DEBUG (1505): d0 414000003f800000 d1 2073646565637834 I/DEBUG (1505): d2 4de4b8bc426fb934 d3 42c80000007a1f34 I/DEBUG (1505): d4 00000008004930e0 d5 0000000000000000 I/DEBUG (1505): d6 0000000000000000 d7 4080000080000000 I/DEBUG (1505): d8 0000025843e7c000 d9 c0c0000040c00000 I/DEBUG (1505): d10 40c0000040c00000 d11 0000000000000000 I/DEBUG (1505): d12 0000000000000000 d13 0000000000000000 I/DEBUG (1505): d14 0000000000000000 d15 0000000000000000 I/DEBUG (1505): d16 afd4242840704ab8 d17 0000000000000000 I/DEBUG (1505): d18 0000000000000000 d19 0000000000000000 I/DEBUG (1505): d20 0000000000000000 d21 0000000000000000 I/DEBUG (1505): d22 0000000000000000 d23 0000000000000000 I/DEBUG (1505): d24 0000000000000000 d25 0000000000000000 I/DEBUG (1505): d26 0000000000000000 d27 0000000000000000 I/DEBUG (1505): d28 00ff00ff00ff00ff d29 00ff00ff00ff00ff I/DEBUG (1505): d30 0000000000000000 d31 3fe55167807de022 I/DEBUG (1505): scr 68000012
합니다. Segfault 이하 (sig11). 정의상 segfault는 항상 버그입니다. 이것은 네이티브 코드 처리 GC 및/또는 mem-limit 검사에서 절대적으로 안드로이드 버그입니다. 하지만 여전히 나쁜 리뷰, 반품 및 낮은 판매로 인한 충돌 애플 리케이션이야.
그래서 제한을 직접 계산해야합니다.
나는 여기에서 고생했다. 픽셀 (EpicPixels)을 직접 추가하려고 시도했지만, 여전히 memcrash가 주기적으로 충돌하여 뭔가를 적게 계산하고 있습니다. 나는 javaBytes (total-free)를 NativeHeapAllocSize에 추가하려고 시도했으나,이 때가되면 내 앱이 "식욕 돋우는 음식"이되고, 아무것도 제거 할 때까지 비트 맵을 해제하고 해제하게됩니다.
사람이 java.lang.OutOfMemory을 메모리 제한을 계산하고 실행하는 데 사용되는 정확한 계산을 알고 있나요?
다른 누구도이 문제를 겪었습니까? 당신은 지혜의 진주가 있습니까?-
Google 직원 중 누가이 계획을 꿈꾸 었는지 알 수있는 사람이 누구든지 내 인생의 40 시간을 망치기 위해 펀치 할 수 있습니까? J/K
ANSWER : 한계 NativeHeapAllocSize < maxMemory()에 대해이고; 그러나 메모리 조각화로 인해 Android는 실제 제한보다 훨씬 이전에 충돌합니다. 따라서 실제 한계보다 약간 작은 값으로 자신을 제한해야합니다. 이 "안전 요인"은 앱에 따라 다르지만 대부분의 사람들에게는 MiB가 작동하는 것으로 보입니다. (방금이 동작이 어떻게 부러 졌는지 날아가 버렸다고 말할 수 있습니까?)
이것은 사용을 종료 한 코드와 매우 유사합니다. true/false를 반환하는 대신, bitmap.recycle()을 사용하여 공간을 확보합니다 ... –
시도해 보았지만 checkBitmapFitsInMemory()를 사용하면 false를 반환하고 checkBitmapFitsInMemory()를 사용하지 않으면 앱이로드됩니다. 충돌이없는 비트 맵. 내 기록 된 값 : bmpwidth = 93, bmpheight = 131, bmpdensity = 2, reqsize = 24366, heapPad = 4194304, allocNativeHeap = 33150304, maxMemory = 33554432. 비슷한 방법을 쓰는 방법에 대한 아이디어는 있지만 그게 더 효과적일까요? – Geltrude
비트 맵이 더 이상 기본 힙에 저장되지 않으므로이 코드는 Honeycomb 이상에서는 작동하지 않습니다. – vomitcuddle