Android 引起:java.lang.OutOfMemoryError:位图大小超出VM预算
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10314527/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budget
提问by Sniper
In my application when I try to launch it Force Closed and the error pointing the line "setContentView(R.layout.Menu);" of the layout. And in the XML file it show the "OutOfMemoryError" image view in my layout. I am realy confused. Please guide me for further move.
在我的应用程序中,当我尝试启动它时强制关闭并且错误指向“setContentView(R.layout.Menu);”行 的布局。在 XML 文件中,它在我的布局中显示“OutOfMemoryError”图像视图。我真的很困惑。请指导我进一步的行动。
Edited:
编辑:
My application uses database, and at the very first time it parse some XML data and insert into the Sqlite database. My Outofmemory problem occurs only at the first time. Second time it works fine. I tried System.gc(). Is there any prob on that.
我的应用程序使用数据库,并且在第一次解析一些 XML 数据并插入到 Sqlite 数据库中。我的内存不足问题仅在第一次出现。第二次它工作正常。我试过 System.gc()。有什么问题吗。
This is my Log:
这是我的日志:
E/dalvikvm-heap(2712): 105376-byte external allocation too large for this process.
VM won't let us allocate 105376 bytes
FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.Test/com.Test.Menu}: android.view.InflateException: Binary XML file line #13: Error inflating class <unknown>
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1647)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1663)
at android.app.ActivityThread.access00(ActivityThread.java:117)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:130)
at android.app.ActivityThread.main(ActivityThread.java:3683)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
at dalvik.system.NativeStart.main(Native Method)
Caused by: android.view.InflateException: Binary XML file line #13: Error inflating class <unknown>
at android.view.LayoutInflater.createView(LayoutInflater.java:518)
at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:568)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:623)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:626)
at android.view.LayoutInflater.inflate(LayoutInflater.java:408)
at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
at android.view.LayoutInflater.inflate(LayoutInflater.java:276)
at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:207)
at android.app.Activity.setContentView(Activity.java:1657)
at com.Test.Menu.onCreate(Menu.java:32)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1611)
... 11 more
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Constructor.constructNative(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:415)
at android.view.LayoutInflater.createView(LayoutInflater.java:505)
... 23 more
Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budget
at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:460)
at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:336)
at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:697)
at android.content.res.Resources.loadDrawable(Resources.java:1709)
at android.content.res.TypedArray.getDrawable(TypedArray.java:601)
at android.widget.ImageView.<init>(ImageView.java:118)
at android.widget.ImageView.<init>(ImageView.java:108)
This is my XML code:
这是我的 XML 代码:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/RL_Title"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="8"
android:onClick="onTitleClick" >
<ImageView
android:id="@+id/Img_Title_bg"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="center"
android:src="@drawable/title_bg" />
<Button
android:id="@+id/Btn_Title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginRight="5dp"
android:background="@drawable/title_al"
android:drawableRight="@drawable/pro"
android:gravity="center"
android:onClick="onTitleClick" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/RL_MainMenu"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1" android:onClick="onDoNothing">
<ImageView
android:id="@+id/ImageView01"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="4"
android:src="@drawable/main_bg" android:scaleType="centerCrop"/>
<ImageView
android:id="@+id/Img_logo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="4"
android:scaleType="center"
android:src="@drawable/logo_al" />
<LinearLayout
android:id="@+id/LI_Menu"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/RL_ExtraOption"
android:layout_alignTop="@+id/Img_logo"
android:layout_margin="2dp"
android:orientation="vertical" >
<ImageButton
android:id="@+id/Img_Buyer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="1dp"
android:layout_weight="1"
android:background="@drawable/bt_blink"
android:onClick="Nextclick"
android:scaleType="fitCenter"
android:soundEffectsEnabled="true"
android:src="@drawable/buyer_icon" />
<ImageButton
android:id="@+id/Img_Seller"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="1dp"
android:layout_weight="1"
android:background="@drawable/bt_blink"
android:onClick="Nextclick"
android:scaleType="fitCenter"
android:src="@drawable/seller_icon" />
<ImageButton
android:id="@+id/Img_Lender"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="1dp"
android:layout_weight="1"
android:background="@drawable/bt_blink"
android:onClick="Nextclick"
android:scaleType="fitCenter"
android:src="@drawable/lender_icon" />
<ImageButton
android:id="@+id/Img_myTitleRep"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="1dp"
android:layout_weight="1"
android:background="@drawable/bt_blink"
android:onClick="Nextclick"
android:scaleType="fitCenter"
android:src="@drawable/my_title_rep_icon_al" />
<ImageButton
android:id="@+id/Img_Setup"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="1dp"
android:layout_weight="1"
android:background="@drawable/bt_blink"
android:onClick="Nextclick"
android:scaleType="fitCenter"
android:src="@drawable/setup_icon" />
</LinearLayout>
<RelativeLayout
android:id="@+id/RL_ExtraOption"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="@drawable/main_bottom_bg" >
<TextView
android:id="@+id/txt_RepName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:textColor="@color/white"
android:textSize="@dimen/font_size" />
<TableRow
android:id="@+id/TR_ContactRep"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:gravity="center" >
<Button
android:id="@+id/Btn_ContactRep"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="3dp"
android:background="@drawable/contact_rep_blink"
android:onClick="ContactRep_Click" />
<Button
android:id="@+id/Btn_MoreOption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:background="@drawable/main_more_blink"
android:onClick="onMoreClick" />
</TableRow>
</RelativeLayout>
<LinearLayout
android:id="@+id/ln_Mainmore"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/dialog_bg" android:layout_alignParentBottom="true" android:visibility="gone">
<LinearLayout
android:id="@+id/LinearLayout02"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="3"
android:orientation="vertical" >
</LinearLayout>
<TableLayout
android:id="@+id/TableLayout01"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center" >
<TableRow
android:id="@+id/TableRow04"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5dp"
android:layout_marginTop="20dp"
android:gravity="center" >
<Button
android:id="@+id/Btn_Rate"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/property_blue_blink"
android:onClick="onRate"
android:singleLine="true"
android:text="Rate/Testimonial"
android:textColor="@color/white"
android:textSize="@dimen/font_size"
android:textStyle="bold" />
</TableRow>
<TableRow
android:id="@+id/TableRow01"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5dp"
android:gravity="center" >
<Button
android:id="@+id/btn_SubFeature"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/property_blue_blink"
android:onClick="onSubFeature"
android:singleLine="true"
android:text="Submit A Feature"
android:textColor="@color/white"
android:textSize="@dimen/font_size"
android:textStyle="bold" />
</TableRow>
<TableRow
android:id="@+id/TableRow03"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5dp"
android:gravity="center" >
<Button
android:id="@+id/Btn_ReferFrnd"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/property_blue_blink"
android:onClick="onReferAFrnd"
android:text="Refer A Friend"
android:textColor="@color/white"
android:textSize="@dimen/font_size"
android:textStyle="bold" />
</TableRow>
<TableRow
android:id="@+id/TableRow02"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5dp"
android:gravity="center" >
<Button
android:id="@+id/Btn_cancel"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/property_cancel_blink"
android:onClick="onClose"
android:text="Cancel"
android:textColor="@color/black"
android:textSize="@dimen/font_size"
android:textStyle="bold" />
</TableRow>
</TableLayout>
<LinearLayout
android:id="@+id/linearLayout2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="3"
android:orientation="vertical" >
</LinearLayout>
</LinearLayout>
</RelativeLayout>
回答by N-JOY
I guess the problem is not in your layout; the problem is somewhere else in your code. And you are probably leaking context somewhere.
我想问题不在于您的布局;问题出在您的代码中的其他地方。而且您可能正在某处泄漏上下文。
Other probable reason is that you must be creating bulky multiple objects while parsing your XML (as you mentioned this occurs the first time when you parse XML). Though Java has auto garbage collection approach, but still you can not completely rely on it. It is a good practice to nullify your collection instance or clear your objects content when you don't need them any more.
其他可能的原因是您在解析 XML 时必须创建庞大的多个对象(正如您提到的,这发生在您第一次解析 XML 时)。虽然 Java 有自动垃圾回收的方法,但你仍然不能完全依赖它。当您不再需要它们时,取消您的集合实例或清除您的对象内容是一个很好的做法。
But still I have prepared a list of important points which you should remember while dealing with bitmaps on Android.
但是我仍然准备了一个重要的要点列表,您在处理 Android 上的位图时应该记住这些要点。
1)You can call recycle on each bitmap and set them to null. (bitmap.recycle()
will release all the memory used by this bitmap, but it does not nullify the bitmap object).
1)您可以在每个位图上调用 recycle 并将它们设置为 null。(bitmap.recycle()
将释放此位图使用的所有内存,但不会使位图对象无效)。
2)You can also unbind the drawables
associated with layouts when an activity is destroyed. Try the code given below and also have a look at this link link.
2)您还可以drawables
在活动被销毁时解除关联布局。试试下面给出的代码,也看看这个链接链接。
private void unbindDrawables(View view) {
if (view.getBackground() != null) {
view.getBackground().setCallback(null);
}
if (view instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
unbindDrawables(((ViewGroup) view).getChildAt(i));
}
((ViewGroup) view).removeAllViews();
}
}
// Call this method from onDestroy()
void onDestroy() {
super.onDestroy();
unbindDrawables(findViewById(R.id.RootView));
System.gc();
}
3)You can convert your hashmaps
to WeakHashmaps
, so that its memory would get released when the system runs low on memory.
3)您可以将您的 转换hashmaps
为WeakHashmaps
,以便在系统内存不足时释放其内存。
4)You can scale/resize all your bitmaps. To scale bitmaps you can try something like this:
4)您可以缩放/调整所有位图的大小。要缩放位图,您可以尝试以下操作:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
Bitmap preview_bitmap=BitmapFactory.decodeStream(is, null, options);
This inSampleSize option reduces memory consumption.
这个 inSampleSize 选项减少了内存消耗。
Here's a complete method. First it reads the image size without decoding the content itself. Then it finds the best inSampleSize value; it should be a power of 2. And finally the image is decoded.
这里有一个完整的方法。首先它读取图像大小而不解码内容本身。然后它找到最好的 inSampleSize 值;它应该是 2 的幂。最后图像被解码。
// 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);
// The new size we want to scale to
final int REQUIRED_SIZE=70;
// Find the correct scale value. It should be the power of 2.
int scale=1;
while(o.outWidth/scale/2 >= REQUIRED_SIZE && o.outHeight/scale/2 >= REQUIRED_SIZE)
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;
}
Have a look at this link..
看看这个链接。.
5)You can override onLowMemory()
method in an activity which gets a call when entire system runs low on memory. You can release a few resources there.
5)您可以onLowMemory()
在整个系统内存不足时调用的活动中覆盖方法。你可以在那里释放一些资源。
6)You can make your objects SoftReference
or Weakreference
, so that they get released in a low-memory condition.
6)您可以制作您的对象SoftReference
or Weakreference
,以便它们在低内存条件下被释放。
A very common memory leak that I observed is due to the implementation of inner classes and implementing Handler
in Activity
. This links talks about the same in more detail.
我观察到的一个非常常见的内存泄漏是由于内部类的实现Handler
和Activity
. 此链接更详细地讨论了相同的内容。
I hope this helps to eliminate your problem.
我希望这有助于解决您的问题。
回答by Andreas Kl?ber
This is a typical problem when using Android's ImageView
with large images on older devices (even if the file size is only several Kbs). The native graphics library called skiathat is used to decode the image allocates native memory based on the image's dimensions, so the file size does not influence this directly.
这是ImageView
在旧设备上使用带有大图像的Android 时的典型问题(即使文件大小只有几个 Kbs)。用于解码图像的称为skia 的本机图形库根据图像的尺寸分配本机内存,因此文件大小不会直接影响这一点。
Even if you omit the src
-attribute in the XML layout definition to load the image yourself in your onCreate()
method the same error will be triggered. The only way to get around this is to use an inSampleSize
in BitmapFactory.decodeStream
to perform downsampling directly during decoding (see Strange out of memory issue while loading an image to a Bitmap objectfor example). This itself raises the question of how to determine this scale factor.
即使您省略了src
XML 布局定义中的-attribute 以在您的onCreate()
方法中自己加载图像,也会触发相同的错误。解决此问题的唯一方法是在解码期间直接使用inSampleSize
inBitmapFactory.decodeStream
执行下采样(例如,请参阅将图像加载到位图对象时出现的奇怪的内存不足问题)。这本身就提出了如何确定这个比例因子的问题。
The best solution I found when handling large images is replacing the ImageView
with a WebView
and load some minimal HTML like this:
我在处理大图像时找到的最佳解决方案是用ImageView
a替换WebView
并加载一些最小的 HTML,如下所示:
webView.loadUrl("file:///android_res/raw/background.html");
where the content of raw/background.html
might be something like this:
的内容raw/background.html
可能是这样的:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<style type="text/css">
body {
margin: 0;
}
img {
width: 100%;
height: auto;
display: block;
}
</style>
</head>
<body>
<img src="file:///android_res/drawable/background.png" />
</body>
The WebKit engine that is used in the WebView performs image loading in a much more efficient way, so that those memory allocation errors should be gone.
WebView 中使用的 WebKit 引擎以更有效的方式执行图像加载,因此应该消除那些内存分配错误。
You can even use different images for portrait and landscape by putting them in drawable-port
and drawable-land
. But then you have to call clearCache(false)
on the WebView instance in your onDestroy()
method because otherwise the image cached on the first load will always be used (disabling caching on the WebView instance does not work).
您甚至可以将不同的图像用于纵向和横向,将它们放入drawable-port
和 中drawable-land
。但是随后您必须clearCache(false)
在onDestroy()
方法中调用WebView 实例,否则将始终使用第一次加载时缓存的图像(禁用 WebView 实例上的缓存不起作用)。
回答by Mark Kazakov
After spending a lot of time on this problem I found the solution! All you need to do is ask for more memory. Place this code inside your android manifest under:
在这个问题上花了很多时间后,我找到了解决方案!您需要做的就是请求更多内存。将此代码放在您的 android 清单中:
<application>:
Put:
放:
android:largeHeap="true"
Worked great for me! Please note that this solution works only on API 11 and above.
对我来说很棒!请注意,此解决方案仅适用于 API 11 及更高版本。
More info here.
更多信息在这里。
回答by Krishnakant Dalal
A lot of devices have very limited and restricted memory available to each device. A lot of older devices allocate 16MB of memory to your application, while some more modern devices might allocate 24MB or even 32MB (I've seen a device with only 14MB).
许多设备的每个设备可用的内存非常有限。许多旧设备为您的应用程序分配 16MB 内存,而一些更现代的设备可能会分配 24MB 甚至 32MB(我见过只有 14MB 的设备)。
Whenever you load so many images into memory, this space fills up very quickly causing the OutOfMemoryError to be thrown. To overcome this problem, you should (as previous answers have said) shrink the images to thumbnails and only keep the thumbnails in device memory (reduced memory footprint) and have the images saved to SDCARD.
每当您将如此多的图像加载到内存中时,此空间会很快填满,从而引发 OutOfMemoryError。为了克服这个问题,您应该(如之前的答案所述)将图像缩小为缩略图,并且仅将缩略图保留在设备内存中(减少内存占用)并将图像保存到 SDCARD。
You can see how much memory your program is using from the DDMS layout in Eclipse. I believe you can also override the Application class to listen for a "Low Memory" warning function.
您可以从 Eclipse 中的 DDMS 布局中查看您的程序使用了多少内存。我相信您还可以覆盖 Application 类来侦听“低内存”警告功能。
When you read in the Bitmap through the BitmapFactory, set the BitmapFactory.Option inScaled parameter to 2 or 4 (or whatever works for you) to create a smaller, less memory intensive image.
当您通过 BitmapFactory 读取位图时,将 BitmapFactory.Option inScaled 参数设置为 2 或 4(或任何适合您的值)以创建更小、内存占用更少的图像。
Generally, there is only one solution: use smaller images. If there's no code it's hard to say what's exactly wrong. You may try to lower image size.
通常,只有一种解决方案:使用较小的图像。如果没有代码,很难说到底出了什么问题。您可以尝试降低图像尺寸。
回答by android developer
in addition to what people have written here , i suggest watching this video of google , which point to some common memory issues and how to find the cause to your memory problem:
除了人们在这里写的内容之外,我建议观看谷歌的这个视频,它指出了一些常见的内存问题以及如何找到内存问题的原因:
回答by Prakash
It seams like ur image is big size so u can decode your image and use android:largeHeap="true".inside manifest of Application Tag
它看起来像你的图像很大,所以你可以解码你的图像并使用 android:largeHeap="true"。应用程序标签的内部清单
回答by Hasan Shouman
I had the same problem before and I was debugging on S4 android 4.3. The solution was : Copy the images from the mdpi folder to hdpi folder (so they are now on both folder)
我之前遇到过同样的问题,我正在 S4 android 4.3 上进行调试。解决方案是:将图像从 mdpi 文件夹复制到 hdpi 文件夹(因此它们现在位于两个文件夹中)
I know weird! but this solved my problem.
我知道奇怪!但这解决了我的问题。
回答by Narasimha
you might have gone through all the above solutions, but still give it a try. I was lost in finding a solution until I got it work. This might night work for your case (Excuse me in that case).
您可能已经完成了上述所有解决方案,但仍然可以尝试一下。在找到解决方案之前,我迷失了方向。这可能适合您的情况(在这种情况下对不起)。
myIntent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_CLEAR_TASK); myIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
myIntent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_CLEAR_TASK); myIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
place these before you call your activity.
在您调用您的活动之前放置这些。