巨大的内存增加(本地堆)设置布局

3

我预计增加0.1MB,但实际上本地堆使用量增加了6MB。

下面是我的计算过程:

Log.d("test", "before setting layout");
showMemoryStats();

setContentView(R.layout.my_layout);

Log.d("test", "after setting layout");
showMemoryStats();

showMemoryStats是什么:

public static void showMemoryStats() {
    Log.i("test", "----------------------------------------------------------------------------------------------------------------------------");
    Log.i("test", "showing memory stats in xx");
    double nativeUsage = Debug.getNativeHeapAllocatedSize(); 
    Log.i("test", "nativeUsage: " + nativeUsage);
    //current heap size 
    double heapSize =  Runtime.getRuntime().totalMemory();
    Log.i("test", "heapSize: " + heapSize);
    //amount available in heap 
    double heapRemaining = Runtime.getRuntime().freeMemory();   
    Log.i("test", "heapRemaining: " + heapRemaining);
    double memoryAvailable = Runtime.getRuntime().maxMemory() - (heapSize - heapRemaining) - nativeUsage;
    Log.i("test", "memoryAvailable: " + memoryAvailable);
    Log.i("test", "----------------------------------------------------------------------------------------------------------------------------");
}

输出结果:
``` 07-03 16:50:40.127: D/test(18647): 设置布局前 07-03 16:50:40.127: I/test(18647): ---------------------------------------------------------------------------------------------------------------------------- 07-03 16:50:40.127: I/test(18647): 在xx中显示内存统计信息 07-03 16:50:40.127: I/test(18647): nativeUsage: 5706008.0 07-03 16:50:40.127: I/test(18647): heapSize: 4905968.0 07-03 16:50:40.127: I/test(18647): heapRemaining: 1815456.0 07-03 16:50:40.127: I/test(18647): memoryAvailable: 2.4757912E7 07-03 16:50:40.127: I/test(18647): ---------------------------------------------------------------------------------------------------------------------------- 07-03 16:50:40.348: D/dalvikvm(18647): GC_EXTERNAL_ALLOC释放了100K,49%的内存空闲,总共2924K/5639K,外部0K/0K,暂停了45ms 07-03 16:50:40.518: D/dalvikvm(18647): GC_EXTERNAL_ALLOC释放了9K,49%的内存空闲,总共2917K/5639K,外部2700K/3371K,暂停了51ms 07-03 16:50:40.638: D/dalvikvm(18647): GC_EXTERNAL_ALLOC释放了4K,49%的内存空闲,总共2928K/5639K,外部3952K/4356K,暂停了51ms 07-03 16:50:40.698: D/dalvikvm(18647): GC_EXTERNAL_ALLOC释放了2K,48%的内存空闲,总共2933K/5639K,外部5963K/6027K,暂停了24ms 07-03 16:50:40.718: D/test(18647): 设置布局后 07-03 16:50:40.718: I/test(18647): ---------------------------------------------------------------------------------------------------------------------------- 07-03 16:50:40.718: I/test(18647): 在xx中显示内存统计信息 07-03 16:50:40.718: I/test(18647): nativeUsage: 1.2101904E7 07-03 16:50:40.718: I/test(18647): heapSize: 4734944.0 07-03 16:50:40.718: I/test(18647): heapRemaining: 1716432.0 07-03 16:50:40.718: I/test(18647): memoryAvailable: 1.8434016E7 07-03 16:50:40.718: I/test(18647): ---------------------------------------------------------------------------------------------------------------------------- ```

具体计算如下:

12101856字节 - 5703424字节 = 6398432字节 = 6.10202 mb

我检查了我的布局文件并添加了所有使用的drawable的大小,总大小为124 kb -> 0.121094 mb

那么到底是什么导致本机堆增加了6 MB?

如果有人要求,我可以放置布局文件,不知道是否有意义...只是一堆带有id和drawable的布局,正如我所说,我已经检查过了drawable的大小。

非常感谢提前...

编辑:这是解决方案,在我的情况下 - 为了总结反应和评论:我将图像存储在“drawable”文件夹中,并使用hdpi设备。解决方案:将图像放入文件夹drawable-hdpi中。原因:系统正在从“drawable”中拉伸我的图像以匹配hdpi分辨率,尽管它们已经具有hdpi分辨率。这使它们占用的内存比它们应该多出2倍以上。


你是否正在使用占用更多内存的内容来填充可绘制对象?你的可绘制对象是什么?图片还是字段? - IAmGroot
可绘制对象是位图或XML文件,引用按下/可绘制状态的位图。没有更多。填充:我正在使用动态数据进行填充,但在这些行之后。如您所见,有一个输出,然后是setContentView,然后再次输出,在中间没有其他内容。 - User
2个回答

1
问题在于当Android需要在屏幕上绘制您的可绘制对象时,它们比在res文件夹中时要大得多。如果您有一个100Kb的PNG文件,则这是压缩大小。当Android在屏幕上绘制PNG时,它会将其放大到默认大小,即(4个字节)*(像素高度)*(像素宽度)。这是因为它为图像的每个像素存储4个字节的颜色信息。这意味着,如果您的图像例如为800 x 600像素,则Android生成的结果位图为800x600x4字节= 1920000字节= 约2 Mb。
如果您想解决此问题,您必须使用较小的图像。

1
@Doomsknight已经解释得非常准确了。奇怪的是你的大小为4 MB。你从哪里得到这个数字的? - Dude
嗨。我用两个png图像进行了测试,都是480 x 800。其中一个有透明区域,另一个没有。没有透明区域的图像大小为1.7 mb,另一个大小为3.456 mb(因为它稍微大了一点,所以将其缩小了)。我使用 background = ((BitmapDrawable)myRootView.getBackground()).getBitmap(); Log.d("test", "size of img: " + (background.getRowBytes() * background.getHeight() / 1000000d)); 获取了这个结果,并跟踪本地堆大小。 - User
1
如果您使用getByteCount()并除以1024 * 1024(一个KiloByte是1024个字节),那么您会得到什么? background = ((BitmapDrawable)myRootView.getBackground()).getBitmap(); Log.d("test", "size of img: " + (background.getByteCount() / 1048576d)); - Dude
background.getByteCount() 只适用于 API 等级 12 及以上。如果可用,这绝对是更好的选择。尝试记录 background.getHeight()background.getWidth(),以查看在读取时实际的高度和宽度是什么。 - IAmGroot
@Doomsknight,这让我接近问题了,得到了1200 x 700!我使用了一个我在某个地方找到的方法,使用BitmapFactory.Options等记录了宽度和高度,但是那返回的是原始图像的尺寸,而不是视图上的。现在我直接记录位图的尺寸,得到了1200 x 700。但为什么会这样呢?屏幕是480 x 800,图像也是480 x 800。也许Android根据文件夹加载不同的分辨率?我将其存储在“drawable”中。 - User
显示剩余4条评论

1

位图占用大量空间。

每个像素需要4个字节!

因此,一个100万像素的图像就是4MB!我猜你正在使用许多较小的图像,但它们很快就会累加起来。

解决这个问题的一种方法是以较低的分辨率加载位图(在大多数情况下,您不会注意到任何区别,因为它们并没有以最大分辨率显示)。请查看BitmapFactory.Options.inSampleSize

引用自Android:

位图占用大量内存,特别是对于像照片这样的丰富图像。例如,Galaxy Nexus相机拍摄的照片高达2592x1936像素(500万像素)。如果使用的位图配置是ARGB_8888(从Android 2.3开始的默认值),则将此图像加载到内存中需要约19MB的内存(2592*1936*4字节),立即耗尽某些设备上的每个应用程序限制。

这里有一个很好的链接可以更好地解释


@Ixx 你好。解决方案在给定的链接中。特别是第一课。它有很棒的代码片段,我也用它来缩小图像。你只需传递所需的图像大小,它就会计算并使用BitmapFactory.Options.inSampleSize适当地缩小它。 - IAmGroot
我还要考虑回收和其他技巧,因为我会在各个地方加载很多不同的东西... 这只是开始... 但是,如果它看起来仍然完美,缩小规模是个好主意,否则我会遇到问题... - User
@Ixx 这样大小的图像只需要1.5MB (480x800x4 Bytes)。根据您需要的颜色丰富程度,您可以使用 ARGB_4444 代替。这将再次减半大小,但也会大幅减少可用的颜色数量。如果您不需要透明度(我假设您的背景不需要),那么请使用 RGB_256。这将为您提供大量的颜色,并且存储空间比其他格式更小。- 绝对必备。 - IAmGroot
实际上应该是 Bitmap.Config.RGB_565 而不是 256 - IAmGroot
请查看我在Dude的帖子中的最后一条评论,我使用了一个具有透明区域的480x800图像,大小为3.4 mb。我认为应该使用ARGB_8888,因为我没有设置任何东西。所以它应该像你说的那样是480x800x4,但实际上不是...在我的评论中,我写了如何得到这个大小。 - User
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接