Android : 2MB 여유 힙이있는 400KB 파일의 BitmapFactory.decodeStream () 메모리 부족
내 앱에서 소스의 다음 줄에서 OOM 오류가 발생합니다.
image = BitmapFactory.decodeStream(assetManager.open(imgFilename));
OOM 오류로 인해 앱이 종료되는 할당 직전 :
(...)
08-05 21:22:12.443: I/dalvikvm-heap(2319): Clamp target GC heap from 25.056MB to 24.000MB
08-05 21:22:12.443: D/dalvikvm(2319): GC_FOR_MALLOC freed <1K, 50% free 2709K/5379K, external 18296K/19336K, paused 58ms
08-05 21:22:14.513: D/dalvikvm(2319): GC_EXTERNAL_ALLOC freed <1K, 50% free 2709K/5379K, external 18296K/19336K, paused 101ms
08-05 21:22:14.903: I/dalvikvm-heap(2319): Clamp target GC heap from 25.073MB to 24.000MB
08-05 21:22:14.903: D/dalvikvm(2319): GC_FOR_MALLOC freed 0K, 50% free 2709K/5379K, external 18312K/19336K, paused 53ms
08-05 21:22:22.843: D/ddm-heap(2319): Heap GC request
08-05 21:22:22.963: I/dalvikvm-heap(2319): Clamp target GC heap from 25.073MB to 24.000MB
08-05 21:22:22.963: D/dalvikvm(2319): threadid=1: still suspended after undo (sc=1 dc=1)
08-05 21:22:22.963: D/dalvikvm(2319): GC_EXPLICIT freed 1K, 50% free 2710K/5379K, external 18312K/19336K, paused 116ms
DDMS는 힙 상태에 대한 유사한 그림을보고합니다.
Heap Size: 5.254 MB
Allocated: 2.647 MB
Free: 2.607 MB
%Used: 50.38%
#Objects 49,028
이 줄을 한 번만 실행하면 OOM 오류가 발생합니다.
08-05 21:26:04.783: D/dalvikvm(2319): GC_EXTERNAL_ALLOC freed <1K, 50% free 2710K/5379K, external 18312K/19336K, paused 57ms
08-05 21:26:05.023: E/dalvikvm-heap(2319): 2097152-byte external allocation too large for this process.
08-05 21:26:05.163: I/dalvikvm-heap(2319): Clamp target GC heap from 25.073MB to 24.000MB
08-05 21:26:05.163: E/GraphicsJNI(2319): VM won't let us allocate 2097152 bytes
08-05 21:26:05.163: D/dalvikvm(2319): GC_FOR_MALLOC freed 0K, 50% free 2710K/5379K, external 18312K/19336K, paused 30ms
08-05 21:26:05.283: D/skia(2319): --- decoder->decode returned false
- "imgFileName"이 참조하는 파일의 크기는 Windows에서 400K 미만으로보고됩니다. 그렇다면 BitmapFactory.decodeStream이 2MB를 할당하려고하는 이유는 무엇입니까?
- 여유 공간이 충분할 때 OOM 오류가 발생하는 이유는 무엇입니까?
이 앱은 Android 2.2 이상을 대상으로합니다.
미리 감사드립니다!
Android 라이브러리는 이미지를로드하는 데 그리 똑똑하지 않으므로 이에 대한 해결 방법을 만들어야합니다.
내 테스트에서 Drawable.createFromStream
보다 더 많은 메모리를 사용합니다 BitmapFactory.decodeStream
.
메모리 (RGB_565)를 줄이기 위해 색 구성표를 변경할 수 있지만 이미지 품질도 저하됩니다.
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Config.RGB_565;
Bitmap bitmap = BitmapFactory.decodeStream(stream, null, options);
참조 : http://developer.android.com/reference/android/graphics/Bitmap.Config.html
메모리 사용량을 많이 줄일 수있는 크기 조정 된 이미지를로드 할 수도 있지만 너무 많은 품질을 잃지 않으려면 이미지를 알아야합니다.
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap bitmap = BitmapFactory.decodeStream(stream, null, options);
참조 : http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html
inSampleSize를 동적으로 정의하려면 결정을 내릴 이미지 크기를 알고 싶을 수 있습니다.
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
bitmap = BitmapFactory.decodeStream(stream, null, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
options.inJustDecodeBounds = false;
// recreate the stream
// make some calculation to define inSampleSize
options.inSampleSize = ?;
Bitmap bitmap = BitmapFactory.decodeStream(stream, null, options);
장치의 화면 크기에 따라 inSampleSize를 사용자 지정할 수 있습니다. 화면 크기를 얻으려면 다음을 수행하십시오.
DisplayMetrics metrics = new DisplayMetrics();
((Activity) activity).getWindowManager().getDefaultDisplay().getMetrics(metrics);
int screenWidth = metrics.widthPixels;
int screenHeight =metrics.heightPixels;
Other tutorials: - http://developer.android.com/training/displaying-bitmaps/load-bitmap.html - http://developer.android.com/training/displaying-bitmaps/index.html
Please see this for a guide on loading large Bitmaps more efficiently:
http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
A 400 KB image file can easily take up 5-10 MB of RAM.
The size of the file on disk doesn't necessarily coincide with the size of the file in memory. Chances are likely that the file is compressed, which they won't be when decoded. You need to account for that in your calculation.
Multiply the size of the image (width x height) by the color depth of the image to get the in-memory size of the image.
Basically you can resolve your issue by trying to scale your Bitmap
and you'll see memory consumption reduced. To do it you can copy he method shown here.
Also, there is a dedicated page at Android Developeres that could help you understand better how to load large Bitmaps. Take a look at the official documentation.
While the above answers are obviously correct, a better practice is also to set explicitly the ImageView's bitmap/src property to null, when they're no longer used, mostly when your activity is being destroyed. Any other heavy duty resources( large text, audio, video) etc. may also be nullified. This ensures that the resources are freed instantly, and not wait for the GC to collect.
I resolved OutOfMemoryError issue using below method
private Bitmap downloadImageBitmap(String sUrl) {
this.url = sUrl;
bitmap = null;
try {
BitmapFactory.Options options = new BitmapFactory.Options();
for (options.inSampleSize = 1; options.inSampleSize <= 32; options.inSampleSize++) {
InputStream inputStream = new URL(sUrl).openStream();
try {
bitmap = BitmapFactory.decodeStream(inputStream, null, options);
inputStream.close();
break;
} catch (OutOfMemoryError outOfMemoryError) {
}
}
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
I change the insample size by 2. My problem is resolved. But be sure that quality of image doesnt get destroy.
'developer tip' 카테고리의 다른 글
번역과 함께 메모리를 복사하는 빠른 방법-ARGB에서 BGR로 (0) | 2020.11.17 |
---|---|
Fragment 내에서 ViewPager 탭 변경 감지 (0) | 2020.11.17 |
std :: __ cxx11 :: string을 std :: string으로 변환 (0) | 2020.11.17 |
Visual Studio에서 푸시되지 않은 나가는 커밋을 제거하는 방법은 무엇입니까? (0) | 2020.11.17 |
Capistrano에서 Git 하위 디렉터리 배포 (0) | 2020.11.17 |