Android内存限制测试问题?

问题描述 投票:2回答:4

我已经读到某个Android应用程序的内存限制为16MB(某些设备可能更高)。所以当从网络加载一些数据(如图像)时,它看起来是正确的。

在我的虚拟设备(适用于Android的Visual Studio模拟器)上,内存限制大约为46MB。我想这是因为我在抛出OutOfMemoryException之前可以加载的图像数是46个图像(每个图像的大小约为1MB)。

起初我以为只有在ImageViews上显示图像时才会超出内存(它们包含在ListView或RecyclerView的项目中)。但是,无论是否显示加载的图像,仍会抛出异常(我可以在输出窗口中看到它)。

所以我想重现OutOfMemoryException,例如加载某种类型的本地列表,例如List<int>,项目数约为13 000 000(应该超过46 MB)。但是不会抛出异常。我甚至尝试将物品数量增加到130,000 000并且仍然相同,不会抛出任何异常。这是代码:

//the local list is declared inside my main Activity class
List<int> _ints = new List<int>();
for(var i = 0; i < 130000000; i++) {
    _ints.Add(i);
}

所以看起来我以错误的方式理解OutOfMemoryException的原因。您能否向我解释一下这个问题,或者如果可能的话,给我一些示例代码或建议来重现OutOfMemoryException,但不涉及从网络下载任何内容,我的意思是尽可能保持最简单。

java c# android memory xamarin.android
4个回答
1
投票

你得到的OutOfMemoryException来自Java方面。您不能仅使用C#对象来重现它。

您需要分配大型Java对象。它不适用于许多小对象,因为可以从C#代码引用多少Java对象是有限制的。

Android.Graphics.Bitmap是一个很好的候选人:

List<Bitmap> _ints = new List<Bitmap>();
for (var i = 0; i < 130000000; i++)
{
    _ints.Add(Bitmap.CreateBitmap(1000, 1000, Bitmap.Config.Argb8888));
}

由此产生的Java异常(包含在单声道异常中):

Java.Lang.OutOfMemoryError: Failed to allocate a 4000012 byte allocation with 219956 free bytes and 214KB until OOM
    at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <368820a9888f43ddb85d18e87189adbf>:0
    at Java.Interop.JniEnvironment+StaticMethods.CallStaticObjectMethod (Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfomethod, Java.Interop.JniArgumentValue* args) [0x00082] in <a043032cf94a485190047a14918b9f60>:0
    at Java.Interop.JniPeerMembers+JniStaticMethods.InvokeObjectMethod (System.String encodedMember, Java.Interop.JniArgumentValue* parameters) [0x00019] in <a043032cf94a485190047a14918b9f60>:0
    at Android.Graphics.Bitmap.CreateBitmap (System.Int32 width, System.Int32 height, Android.Graphics.Bitmap+Config config) [0x0005e] in <3140893b79904cefbb68181cd89998e0>:0
    at SomeActivity.OnCreate (Android.OS.Bundle savedInstanceState) [0x00024] in <efd0cb86bcd8422d9a46a0a8a1804b4d>:0
    at Android.Support.V4.App.FragmentActivity.n_OnCreate_Landroid_os_Bundle_ (System.IntPtr jnienv, System.IntPtr native__this, System.IntPtr native_savedInstanceState) [0x00011] in <71c3e52f1b484794bca1cdfb1b8b1fdb>:0
    at (wrapper dynamic-method) System.Object:46337ec2-c41a-4805-8728-4ab907d01a03 (intptr,intptr,intptr)
    --- End of managed Java.Lang.OutOfMemoryError stack trace ---
  java.lang.OutOfMemoryError: Failed to allocate a 4000012 byte allocation with 219956 free bytes and 214KB until OOM
      at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
      at android.graphics.Bitmap.nativeCreate(Native Method)
      at android.graphics.Bitmap.createBitmap(Bitmap.java:812)
      at android.graphics.Bitmap.createBitmap(Bitmap.java:789)
      at android.graphics.Bitmap.createBitmap(Bitmap.java:756)
      at md53b9888b0c3fe89a24cb980ab2ea2a8a2.SomeActivity.n_onCreate(Native Method)
      at md53b9888b0c3fe89a24cb980ab2ea2a8a2.someActivity.onCreate(SomeActivity.java:32)
      at android.app.Activity.performCreate(Activity.java:5990)
      at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)

编辑:使用Xamarin,内存问题更复杂,因为有两个垃圾收集器,并且两个中都存在一些像位图这样的对象。

这在Xamarin documentation中有解释,特别是章Helping the GC


1
投票
public void OOMTest() throws Exception {
    int count = 20;
    System.out.println("\n=================> started..\n");
    for (int itrator = 1; itrator < 100; itrator++) {
        System.out.println("Iteration " + itrator + " Free Mem: "
                + Runtime.getRuntime().freeMemory());
        int[] memoryFillIntVar = new int[count];
        count = count * 5;
        System.out.println("\nRequired Memory for next loop: " + count);
        Thread.sleep(1000);
    }
}

1
投票

关于应用程序的堆大小,它因手机而异。它是从制造商设置的,最小通常是16MB。您可以通过在Android Manifest中标记它来强制在您的应用中使用更大的堆,但这应该作为最后的手段,因为它会导致系统杀死其他应用程序,以获得可用内存。

在您的情况下,请注意,即使图像未显示,如果另一个对象持有对它的引用,它仍可能仍在应用程序内存中。 Android中的图像加载和管理由于堆的内存限制通常会出现问题。为了克服这个问题,Facebook编写了自己的图像加载库Fresco,它使用不同的堆加载内存,避免使用应用程序中其他对象使用的空间。如果你处理很多图像,请考虑在你的应用程序中介绍它。


1
投票

图像在内存中的大小不是1MB,图像在内存中的实际大小可以计为:

让我们假设你有一个图像2000x1250。它需要4x2000x1250字节的内存。每个像素都有一部分红色,绿色,蓝色和alpha通道信息。

因此,内存中的实际大小将类似于4x2000x1250=10000000 Byte -> 9.5MB

加载图像的最佳方法是使用库,Libraries负责回收位图并加载图像,缓存它们等。

这是收集我最喜欢的,你可以尝试使用任何适合你的需求。我总是喜欢第一个。

GlidePicassoFresco

© www.soinside.com 2019 - 2024. All rights reserved.