Android内存限制测试问题?

时间:2016-10-10 01:59:27

标签: java c# android memory xamarin.android

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

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

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

所以我想通过加载某种类型的本地列表来重现OutOfMemoryException,例如{ perror( "malloc for DrinkMachine failed" ); // the code has failed, so cleanup and exit cleanup(); exit( EXIT_FAILURE ); } ,项目数约为13 000 000(应该超过46 MB)。但是不会抛出异常。我甚至尝试将物品数量增加到1.3亿,但仍然是相同的,没有任何例外。这是代码:

List<int>

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

4 个答案:

答案 0 :(得分: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 :(得分:1)

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

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

答案 2 :(得分: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

答案 3 :(得分:1)

图像占用内存的大小不是1MB,图像在内存中的实际大小可以算作:

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

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

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

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

GlidePicassoFresco