Android的java.lang.OutOfMemoryError?

04-25 08:19:10.111 2431-2603/com.example.francesco.guidedautorewithtabs E/art﹕ Throwing OutOfMemoryError "Failed to allocate a 4194316 byte allocation with 1983651 free bytes and 1937KB until OOM" 04-25 08:19:10.114 2431-2603/com.example.francesco.guidedautorewithtabs E/AndroidRuntime﹕ FATAL EXCEPTION: GLThread 285 Process: com.example.francesco.guidedautorewithtabs, PID: 2431 java.lang.OutOfMemoryError: Failed to allocate a 4194316 byte allocation with 1983651 free bytes and 1937KB until OOM at dalvik.system.VMRuntime.newNonMovableArray(Native Method) at android.graphics.Bitmap.nativeCreate(Native Method) at android.graphics.Bitmap.createBitmap(Bitmap.java:817) at android.graphics.Bitmap.createBitmap(Bitmap.java:794) at android.graphics.Bitmap.createBitmap(Bitmap.java:761) at com.google.maps.api.android.lib6.gmm6.ocla(Unknown Source) at com.google.maps.api.android.lib6.gmm6.ocoa(Unknown Source) at com.google.maps.api.android.lib6.gmm6.ocoa(Unknown Source) at com.google.maps.api.android.lib6.gmm6.ocob(Unknown Source) at com.google.maps.api.android.lib6.gmm6.ocbak.a(Unknown Source) at com.google.maps.api.android.lib6.gmm6.ocbas.a(Unknown Source) at com.google.maps.api.android.lib6.gmm6.oxa(Unknown Source) at com.google.maps.api.android.lib6.gmm6.ola(Unknown Source) at com.google.maps.api.android.lib6.gmm6.olb(Unknown Source) at com.google.maps.api.android.lib6.gmm6.o.cj.g(Unknown Source) at com.google.maps.api.android.lib6.gmm6.o.cj.run(Unknown Source) 

在我的Android代码中,我有很多图片必须显示在不同的片段中。 其中几个存储在资产文件夹,其他从一个http请求拾取。 出于这个原因,我实现了图像caching,以便不违背java.lang.OutOfMemoryError,但是这个错误似乎仍然存在。 我该如何解决这个问题? 在我的图像caching实现下面。

ImageLoader的

 public class ImageLoader { MemoryCache memoryCache=new MemoryCache(); FileCache fileCache; private Map<ImageView, String> imageViews=Collections.synchronizedMap(new WeakHashMap<ImageView, String>()); ExecutorService executorService; private Context context; public ImageLoader(Context context){ this.context=context; fileCache=new FileCache(context); executorService=Executors.newFixedThreadPool(5); } final int stub_id= R.drawable.no_image; public void DisplayImage(String url, ImageView imageView) { imageViews.put(imageView, url); Bitmap bitmap=memoryCache.get(url); if(bitmap!=null) imageView.setImageBitmap(bitmap); else { queuePhoto(url, imageView); imageView.setImageResource(stub_id); } } private void queuePhoto(String url, ImageView imageView) { PhotoToLoad p=new PhotoToLoad(url, imageView); executorService.submit(new PhotosLoader(p)); } private Bitmap getBitmapFromAsset(String strName) { AssetManager assetManager = context.getAssets(); InputStream istr = null; try { istr = assetManager.open(strName); } catch (IOException e) { e.printStackTrace(); } Bitmap bitmap = BitmapFactory.decodeStream(istr); return bitmap; } private Bitmap getBitmap(String url) { File f=fileCache.getFile(url); //from SD cache Bitmap b = decodeFile(f); if(b!=null) return b; //from assets Bitmap bm = getBitmapFromAsset(url); if(bm!=null) return bm; //from web try { Bitmap bitmap=null; URL imageUrl = new URL(url); HttpURLConnection conn = (HttpURLConnection)imageUrl.openConnection(); conn.setConnectTimeout(30000); conn.setReadTimeout(30000); conn.setInstanceFollowRedirects(true); InputStream is=conn.getInputStream(); OutputStream os = new FileOutputStream(f); Utils.CopyStream(is, os); os.close(); bitmap = decodeFile(f); return bitmap; } catch (Throwable ex){ ex.printStackTrace(); if(ex instanceof OutOfMemoryError) memoryCache.clear(); return null; } } //decodes image and scales it to reduce memory consumption private Bitmap decodeFile(File f){ try { //decode image size BitmapFactory.Options o = new BitmapFactory.Options(); o.inJustDecodeBounds = true; BitmapFactory.decodeStream(new FileInputStream(f),null,o); //Find the correct scale value. It should be the power of 2. final int REQUIRED_SIZE=70; int width_tmp=o.outWidth, height_tmp=o.outHeight; int scale=1; while(true){ if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE) break; width_tmp/=2; height_tmp/=2; scale*=2; } //decode with inSampleSize BitmapFactory.Options o2 = new BitmapFactory.Options(); o2.inSampleSize=scale; return BitmapFactory.decodeStream(new FileInputStream(f), null, o2); } catch (FileNotFoundException e) {} return null; } //Task for the queue private class PhotoToLoad { public String url; public ImageView imageView; public PhotoToLoad(String u, ImageView i){ url=u; imageView=i; } } class PhotosLoader implements Runnable { PhotoToLoad photoToLoad; PhotosLoader(PhotoToLoad photoToLoad){ this.photoToLoad=photoToLoad; } @Override public void run() { if(imageViewReused(photoToLoad)) return; Bitmap bmp=getBitmap(photoToLoad.url); memoryCache.put(photoToLoad.url, bmp); if(imageViewReused(photoToLoad)) return; BitmapDisplayer bd=new BitmapDisplayer(bmp, photoToLoad); Activity a=(Activity)photoToLoad.imageView.getContext(); a.runOnUiThread(bd); } } boolean imageViewReused(PhotoToLoad photoToLoad){ String tag=imageViews.get(photoToLoad.imageView); if(tag==null || !tag.equals(photoToLoad.url)) return true; return false; } //Used to display bitmap in the UI thread class BitmapDisplayer implements Runnable { Bitmap bitmap; PhotoToLoad photoToLoad; public BitmapDisplayer(Bitmap b, PhotoToLoad p){bitmap=b;photoToLoad=p;} public void run() { if(imageViewReused(photoToLoad)) return; if(bitmap!=null) photoToLoad.imageView.setImageBitmap(bitmap); else photoToLoad.imageView.setImageResource(stub_id); } } public void clearCache() { memoryCache.clear(); fileCache.clear(); } } 

FileCache

 public class FileCache { private File cacheDir; public FileCache(Context context){ //Find the dir to save cached images if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) cacheDir=new File(android.os.Environment.getExternalStorageDirectory(),"TTImages_cache"); else cacheDir=context.getCacheDir(); if(!cacheDir.exists()) cacheDir.mkdirs(); } public File getFile(String url){ //I identify images by hashcode. Not a perfect solution, good for the demo. String filename=String.valueOf(url.hashCode()); //Another possible solution (thanks to grantland) //String filename = URLEncoder.encode(url); File f = new File(cacheDir, filename); return f; } public void clear(){ File[] files=cacheDir.listFiles(); if(files==null) return; for(File f:files) f.delete(); } } 

的MemoryCache

 public class MemoryCache { private static final String TAG = "MemoryCache"; private Map<String, Bitmap> cache=Collections.synchronizedMap( new LinkedHashMap<String, Bitmap>(10,1.5f,true));//Last argument true for LRU ordering private long size=0;//current allocated size private long limit=1000000;//max memory in bytes public MemoryCache(){ //use 25% of available heap size setLimit(Runtime.getRuntime().maxMemory()/4); } public void setLimit(long new_limit){ limit=new_limit; Log.i(TAG, "MemoryCache will use up to "+limit/1024./1024.+"MB"); } public Bitmap get(String id){ try{ if(!cache.containsKey(id)) return null; //NullPointerException sometimes happen here http://code.google.com/p/osmdroid/issues/detail?id=78 return cache.get(id); }catch(NullPointerException ex){ ex.printStackTrace(); return null; } } public void put(String id, Bitmap bitmap){ try{ if(cache.containsKey(id)) size-=getSizeInBytes(cache.get(id)); cache.put(id, bitmap); size+=getSizeInBytes(bitmap); checkSize(); }catch(Throwable th){ th.printStackTrace(); } } private void checkSize() { Log.i(TAG, "cache size="+size+" length="+cache.size()); if(size>limit){ Iterator<Entry<String, Bitmap>> iter=cache.entrySet().iterator();//least recently accessed item will be the first one iterated while(iter.hasNext()){ Entry<String, Bitmap> entry=iter.next(); size-=getSizeInBytes(entry.getValue()); iter.remove(); if(size<=limit) break; } Log.i(TAG, "Clean cache. New size "+cache.size()); } } public void clear() { try{ //NullPointerException sometimes happen here http://code.google.com/p/osmdroid/issues/detail?id=78 cache.clear(); size=0; }catch(NullPointerException ex){ ex.printStackTrace(); } } long getSizeInBytes(Bitmap bitmap) { if(bitmap==null) return 0; return bitmap.getRowBytes() * bitmap.getHeight(); } } 

utils的

 public class Utils { public static void CopyStream(InputStream is, OutputStream os) { final int buffer_size=1024; try { byte[] bytes=new byte[buffer_size]; for(;;) { int count=is.read(bytes, 0, buffer_size); if(count==-1) break; os.write(bytes, 0, count); } } catch(Exception ex){} } } 

Related of "Android的java.lang.OutOfMemoryError?"

试试这可能会帮助你在清单文件中添加这个标签。

 <application android:largeHeap="true"> </application> 

它会为您的应用程序分配大堆

大量加载大型位图 : http : //developer.android.com/training/displaying-bitmaps/load-bitmap.html

caching位图: http : //developer.android.com/training/displaying-bitmaps/cache-bitmap.html

尝试调整图像大小,并在使用后再循环位图。

 import android.graphics.Bitmap; import android.graphics.BitmapFactory; public class ImageResizer { public static Bitmap decodeSampledBitmapFromFile(String filename, int reqWidth, int reqHeight) { // First decode with inJustDecodeBounds=true to check dimensions final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(filename, options); // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false; return BitmapFactory.decodeFile(filename, options); } public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { // BEGIN_INCLUDE (calculate_sample_size) // Raw height and width of image final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int halfHeight = height / 2; final int halfWidth = width / 2; // Calculate the largest inSampleSize value that is a power of 2 and keeps both // height and width larger than the requested height and width. while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) { inSampleSize *= 2; } // This offers some additional logic in case the image has a strange // aspect ratio. For example, a panorama may have a much larger // width than height. In these cases the total pixels might still // end up being too large to fit comfortably in memory, so we should // be more aggressive with sample down the image (=larger inSampleSize). long totalPixels = width * height / inSampleSize; // Anything more than 2x the requested pixels we'll sample down further final long totalReqPixelsCap = reqWidth * reqHeight * 2; while (totalPixels > totalReqPixelsCap) { inSampleSize *= 2; totalPixels /= 2; } } return inSampleSize; // END_INCLUDE (calculate_sample_size) } } 

这是因为内存不足,你的映像文件的大小很大,要解决这个问题,在你的类中添加这个方法:

 public static Bitmap decodeImageFile(File f,int WIDTH,int HIGHT){ try { //Decode image size BitmapFactory.Options o = new BitmapFactory.Options(); o.inJustDecodeBounds = true; BitmapFactory.decodeStream(new FileInputStream(f),null,o); //The new size we want to scale to final int REQUIRED_WIDTH=WIDTH; final int REQUIRED_HIGHT=HIGHT; //Find the correct scale value. It should be the power of 2. int scale=1; while(o.outWidth/scale/2>=REQUIRED_WIDTH && o.outHeight/scale/2>=REQUIRED_HIGHT) scale*=2; //Decode with inSampleSize BitmapFactory.Options o2 = new BitmapFactory.Options(); o2.inSampleSize=scale; return BitmapFactory.decodeStream(new FileInputStream(f), null, o2); } catch (FileNotFoundException e) {} return null; } 

然后在你使用这个的地方调用这个方法:

 Bitmap b = decodeFile(f); 

使用这个insted:

 Bitmap b = decodeImageFile(f, 1280, 720); 
  <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:largeHeap="true"/> 

OutOfMemoryError是在android中发生的最常见的问题,特别是处理位图。 由于缺less内存空间而无法分配对象,并且垃圾收集器无法释放一些空间时,由Java虚拟机(JVM)抛出此错误。

正如Aleksey所提到的,您可以在清单文件android:hardwareAccelerated =“false”,android:largeHeap =“true”中添加下面的实体,它将适用于某些环境。

 <application android:allowBackup="true" android:hardwareAccelerated="false" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:largeHeap="true" android:supportsRtl="true" android:theme="@style/AppTheme"> 

尝试在将图像加载到内存之前手动调用System.gc(),并且在不需要使用此图像对象时。

你可以试试这个代码….

 BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 8; Bitmap bm = BitmapFactory.decodeFile(img,options); imageView.setImageBitmap(bm);