{"id":1564,"date":"2022-08-30T15:17:35","date_gmt":"2022-08-30T15:17:35","guid":{"rendered":"https:\/\/unknownerror.org\/index.php\/2013\/11\/27\/vm-running-out-of-memory-while-getting-images-from-the-cache-collection-of-common-programming-errors\/"},"modified":"2022-08-30T15:17:35","modified_gmt":"2022-08-30T15:17:35","slug":"vm-running-out-of-memory-while-getting-images-from-the-cache-collection-of-common-programming-errors","status":"publish","type":"post","link":"https:\/\/unknownerror.org\/index.php\/2022\/08\/30\/vm-running-out-of-memory-while-getting-images-from-the-cache-collection-of-common-programming-errors\/","title":{"rendered":"VM running out of memory while getting images from the cache-Collection of common programming errors"},"content":{"rendered":"<p>The problem that I&#8217;m addressing is known to be in devices with 16 mb of heap memory, and I need to solve it. I have threads getting images from a server (Big Images) and having them cached then displayed. The problem is that I run out of memory. To explain a little further I&#8217;m posting my log cat as well as some code:<\/p>\n<pre><code>public class Test extends Activity implements OnClickListener {\nImageView paint, wheels, shadow;\n\nButton b;\nint j = 2;\nint i = 1;\nString pathToWheels, pathToPaint, pathToShadow;\nString stringAngle;\n\n\/** Called when the activity is first created. *\/\n@Override\npublic void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setContentView(R.layout.main);\n\n    MemoryInfo dbm = new MemoryInfo();\n    Debug.getMemoryInfo(dbm);\n    b = (Button) findViewById(R.id.button1);\n    b.setOnClickListener(this);\n\n\n\n    wheels = (ImageView) findViewById(R.id.imageView3);\n    paint = (ImageView) findViewById(R.id.imageView2);\n    shadow = (ImageView) findViewById(R.id.imageView1);\n\n\n\n    while (i &lt; 13) {\n\n        stringAngle = Integer.toString(i);\n        String pathToWheels = url;\n        String pathToPaint = url;\n        String pathToShadow = url;\n\n        if (Cache.getCacheFile(pathToWheels) == null) {\n            ImageDownloader downloader1 = new ImageDownloader(wheels);\n            downloader1\n                    .execute(url);\n        } else if (Cache.getCacheFile(pathToShadow) == null) {\n            ImageDownloader downloader2 = new ImageDownloader(shadow);\n            downloader2\n                    .execute(url);\n\n\n        } else if (Cache.getCacheFile(pathToPaint) == null) {\n\n            ImageDownloader downloader = new ImageDownloader(paint);\n            downloader\n                    .execute(url);\n\n\n        }\n\n        i++;\n\n\n    }\n\n}\n\n\n\n@Override\nprotected void onPause() {\n    super.onPause();\n    Toast.makeText(getApplicationContext(),\"Pause\",\n            Toast.LENGTH_SHORT).show();\n\n}\n\n@Override\npublic void onClick(View v) {\n\n\n    if (v.getId() == R.id.button1) {\n        if (j == 13) \n        {\n            j = 1;  \n        }\n        String s = Integer.toString(j);\n        wheels.setImageBitmap(Cache\n                .getCacheFile(url));\n        paint.setImageBitmap(Cache\n                .getCacheFile(url));\n    shadow.setImageBitmap(Cache\n                .getCacheFile(url));\n        j++;\n\n\n\n    }\n}\n<\/code><\/pre>\n<p>}<\/p>\n<p>From my cache class:<\/p>\n<pre><code>public static void saveCacheFile(String cacheUri, Bitmap image) {\n    if(!isCacheWritable()) return;\n    Log.i(\"CACHE S\",cacheUri);\n    cache.saveCacheFile(cacheUri, image);\n<\/code><\/pre>\n<p>From my CacheStore class:<\/p>\n<pre><code>public Bitmap getCacheFile(String cacheUri) {\n    if(bitmapMap.containsKey(cacheUri)) return (Bitmap)bitmapMap.get(cacheUri);\n\n    if(!cacheMap.containsKey(cacheUri)) return null;\n    String fileLocalName = cacheMap.get(cacheUri);\n    File fullCacheDir = new     File(Environment.getExternalStorageDirectory().toString(),cacheDir);\n    File fileUri = new File(fullCacheDir.toString(), fileLocalName);\n    if(!fileUri.exists()) return null;\n    Log.i(\"CACHE\", \"File \"+cacheUri+\" has been found in the Cache\");\n    Bitmap bm = BitmapFactory.decodeFile(fileUri.toString());\n    Bitmap.createScaledBitmap(bm, 480, 320, true);\n    bitmapMap.put(cacheUri, bm);\n    return bm;\n}\n<\/code><\/pre>\n<p>The app crashes at this line: Bitmap bm = BitmapFactory.decodeFile(fileUri.toString()); where I&#8217;m running out of memory.<\/p>\n<p>My logcat:<\/p>\n<pre><code>    07-06 23:40:20.720: ERROR\/dalvikvm-heap(1844): 691200-byte external allocation too large for this process.\n07-06 23:40:20.720: ERROR\/GraphicsJNI(1844): VM won't let us allocate 691200 bytes\n07-06 23:40:20.770: DEBUG\/skia(1844): --- decoder-&gt;decode returned false\n07-06 23:40:20.790: DEBUG\/AndroidRuntime(1844): Shutting down VM\n07-06 23:40:20.830: WARN\/dalvikvm(1844): threadid=1: thread exiting with uncaught exception (group=0x4001d800)\n07-06 23:40:20.890: ERROR\/AndroidRuntime(1844): FATAL EXCEPTION: main\n07-06 23:40:20.890: ERROR\/AndroidRuntime(1844): java.lang.OutOfMemoryError: bitmap size exceeds VM budget\n07-06 23:40:20.890: ERROR\/AndroidRuntime(1844):     at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)\n07-06 23:40:20.890: ERROR\/AndroidRuntime(1844):     at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:459)\n07-06 23:40:20.890: ERROR\/AndroidRuntime(1844):     at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:271)\n07-06 23:40:20.890: ERROR\/AndroidRuntime(1844):     at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:296)\n07-06 23:40:20.890: ERROR\/AndroidRuntime(1844):     at com.cache.CacheStore.getCacheFile(CacheStore.java:117)\n07-06 23:40:20.890: ERROR\/AndroidRuntime(1844):     at com.cache.Cache.getCacheFile(Cache.java:38)\n07-06 23:40:20.890: ERROR\/AndroidRuntime(1844):     at com.cache.Test.onClick(Test.java:118)\n07-06 23:40:20.890: ERROR\/AndroidRuntime(1844):     at android.view.View.performClick(View.java:2408)\n07-06 23:40:20.890: ERROR\/AndroidRuntime(1844):     at android.view.View$PerformClick.run(View.java:8816)\n07-06 23:40:20.890: ERROR\/AndroidRuntime(1844):     at android.os.Handler.handleCallback(Handler.java:587)\n07-06 23:40:20.890: ERROR\/AndroidRuntime(1844):     at android.os.Handler.dispatchMessage(Handler.java:92)\n07-06 23:40:20.890: ERROR\/AndroidRuntime(1844):     at android.os.Looper.loop(Looper.java:123)\n07-06 23:40:20.890: ERROR\/AndroidRuntime(1844):     at android.app.ActivityThread.main(ActivityThread.java:4627)\n07-06 23:40:20.890: ERROR\/AndroidRuntime(1844):     at java.lang.reflect.Method.invokeNative(Native Method)\n07-06 23:40:20.890: ERROR\/AndroidRuntime(1844):     at java.lang.reflect.Method.invoke(Method.java:521)\n07-06 23:40:20.890: ERROR\/AndroidRuntime(1844):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)\n07-06 23:40:20.890: ERROR\/AndroidRuntime(1844):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)\n07-06 23:40:20.890: ERROR\/AndroidRuntime(1844):     at dalvik.system.NativeStart.main(Native Method)\n<\/code><\/pre>\n<p>Any help would be greatly appreciated, Thanks for reading.<\/p>\n<ol>\n<li>\n<p>You need to re-sample and scale your bitmaps <strong>prior<\/strong> to inserting them into the cache, inside your imagedownloader.<\/p>\n<p>In the past I&#8217;ve had to detect the file size of the image prior to downloading it from the web. If it&#8217;s too large I just use a default image.<\/p>\n<p>Additionally, I also lowered the resolution of the saved image by adjusting the BitmapFactory Sampling size, and adjusted the size of the final image in your app. (this saved a lot of space for the cache).<\/p>\n<p>See How to know the size of a file before downloading it?<\/p>\n<pre><code>\/\/somewhere inside image downloader class...\n{...}\n\nBitmapFactory.Options options = new BitmapFactory.Options();\n\nif(enableSampling)\n    options.inSampleSize = 2;\n\nreturnBitmap = BitmapFactory.decodeStream(is, null, options);   \n\nif(returnBitmap != null)\n{\n\n    if(scaleImage)\n        returnBitmap = Bitmap.createScaledBitmap(returnBitmap, width, height, true);\n\n    \/\/ insert the image into the cache\n    imageCache.put(url, new SoftReference(returnBitmap));\n\n\n    \/\/ Check the ImageView for nulls\n    if(imageView != null &amp;&amp; callback != null){\n        ImageDisplayer displayer = new ImageDisplayer(imageView, returnBitmap, parentView, tag);\n        callback.onImageReceived(displayer);\n    }\n\n}\n\n{...}\n<\/code><\/pre>\n<p>So far this has worked for me, and the check for INSANE file sizes has saved the app from crashing on numerous occasions, not to mention it can just skip downloaing a massive file in the background.<\/p>\n<\/li>\n<li>\n<p>Check out BitmapFactory OOM driving me nuts<\/p>\n<\/li>\n<\/ol>\n<p id=\"rop\"><small>Originally posted 2013-11-27 11:51:58. <\/small><\/p>","protected":false},"excerpt":{"rendered":"<p>The problem that I&#8217;m addressing is known to be in devices with 16 mb of heap memory, and I need to solve it. I have threads getting images from a server (Big Images) and having them cached then displayed. The problem is that I run out of memory. To explain a little further I&#8217;m posting [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1564","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts\/1564","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/comments?post=1564"}],"version-history":[{"count":0,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts\/1564\/revisions"}],"wp:attachment":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/media?parent=1564"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/categories?post=1564"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/tags?post=1564"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}