32g内存 android开发,Android开发高手课之内存优化

内存问题

异常

卡顿 :Java内存不足会导致频繁GC

//通过发送SIGQUIT信号获得ANR日志

adb shell ps -l //查看进程pid

adb shell kill -S QUIT PID

adb pull /data/anr/traces.txt

Android Bitmap内存分配的变化

Android 3.0之前,Bitmap放在Java堆,而像素数据放在Native内存中,如果不手动调用recycle,Bitmap Native内存的回收完全依赖finalize函数回调。

Android 3.0 ~ Android 7.0将Bitmap对象和像素数据统一放到Java堆中,这样即使不调用recycle,Bitmap内存也会随着对象一起被回收。造成的问题是,第一Bitmap内存消耗太大,第二会引起大量的GC。

Android 8.0将Bitmap内存放到Native中,使用NativeAllocationRegistry来辅助回收Native内存,可以做到和对象一起释放,8.0还增加了硬件位图Hardware Bitmap,可以减少图片内存并提升绘制效率。

误区:Native内存不用管

将Bitmap放到native内存中的黑科技

//申请一张空的Native Bitmap

//通过调用libandroid_runtime.so中的Bitmap构造函数,可以得到一张空的Bitmap对象,而它的内存是放到Native堆中。不同版本有差异,需要适配

Bitmap nativeBitmap = nativeCreateBitmap(dstWidth, dstHeight, nativeConfig, 22)

//申请一张普通的Java Bitmap

Bitmap srcBitmap = BitmapFactory.decode(res, id)

//使用java Bitmap将内容绘制到Native Bitmap中

mNativeCanvas.setBitmap(nativeBitmap)

mNativeCanvas.drawBitmap(srcBitmap, mSrcRect, mDstRect, mPaint)

//释放Java Bitmap内存

srcBitmap.recycle()

srcBitmap = null;

以上方法存在的问题:

兼容性问题,需要适配

频繁申请释放Java Bitmap容易导致内存抖动

内存测量方法

adb shell dumpsys meminfo [-d]

Java内存分配

工具:

Allocation Tracker

获取的信息过于分散,中间夹杂着其他的信息

无法做到自动化分析,每次都需要开发者手动开始 / 结束

在停止时,直接把数据dump出来之前,会造成手机卡死

MAT

Native内存分配

Native内存调试的两种方法

Malloc调试:可以调试Native内存的一些使用问题

adb shell setprop wrap. ' "LIBC_DEBUG_MALLOC_OPTIONS=backtrace logwrapper" '

Malloc 钩子:Android P之后,Android的libc支持拦截在程序运行期间发生的所有分配 / 释放调用。

adb shell setprop wrap. ' "LIBC_HOOKS_ENABLE=1" '

设备分级

使用device-year-class的策略对设备分级,对于低端机用户可以关闭复杂动画或者某些功能,使用565格式的图片,使用更小的缓存内存等。

缓存管理,使用onTrimMemory回调,根据不同的状态决定释放多少内存,统一缓存管理可以更好的监控每个模块的缓存大小。

进程模型,减少应用启动的进程数,减少常驻进程

安装包大小,安装包中的代码、资源、图片以及so库的体积,跟他们占用的内存有很大的关系。

Bitmap优化

统一图片库

统一监控

大图片监控:需要注意某张图片内存占用是否过大

重复监控:Bitmap像素数据完全一致的图片

图片总内存:统计应用所有图片占用的内存

内存泄漏

Java内存泄漏

OOM监控

Native内存泄漏监控

针对无法重编so的情况

针对可重编的so情况

内存监控

采集方式

可以每5分钟采集一次PSS、Java堆、图片总内存,采样部分用户

计算指标

内存异常率:可以反映内存占用的异常情况,PSS值可以通过Debug.MemoryInfo拿到

内存UV异常率 = PSS超过400MB的UV / 采集UV

触顶率:可以反映java内存的使用情况

内存UV触顶率 = Java堆占用超过最大堆限制的85%的UV / 采集UV

计算是否触顶的方法

long javaMax = runtime.maxMemory()

long javaTotal = runtime.totalMemory()

long javaUsed = javaTotal - runtime.freeMemory()

float proportion = (float)javaUsed / javaMax

内存分配次数和大小

Debug.getRuntimeStat("art.gc.gc-count")

Debug.getRuntimeStat("art.gc.gc-time")

Debug.getRuntimeStat("art.gc.blocking-gc-count")

Debug.getRuntimeStat("art.gc.blocking-gc-time")

Dalvik日志消息

D/dalvikvm: , , ,

D/dalvikvm( 9050): GC_CONCURRENT freed 2049K, 65% free 3571K/9991K, external 4703K/5261K, paused 2ms+2ms

垃圾回收原因

GC_CONCURRENT:在堆开始占用内存时可以释放的内存的并发垃圾回收

GC_FOR_MALLOC:堆已满而系统不得不停止您的应用程序并回收内存,您的应用尝试分配内存而引起的垃圾回收

GC_HPROF_DUMP_HEAP:当请求创建HPROF文件来分析堆时出现的垃圾回收

GC_EXPLICIT:显示垃圾回收,调用gc()时

GC_EXTERNAL_ALLOC:仅适用于API级别10以及以下,外部分配内存的垃圾回收。

释放量

从此次垃圾回收中回收的内存量

堆统计数据

堆的可用空间百分比与(活动对象数量) / (堆总大小)

外部内存统计数据

API级别10及更低级别的外部分配内存 (已分配内存量) / (发生回收的限制)

暂停时间

堆越大,暂停时间越长,并发暂停时间显示了两个暂停,一个出现在回收开始时,一个出现在回收快要完成时。

ART日志消息

I/art: ( 释放大小) AllocSpace Objects, ( 释放的大型对象大小) LOS objects,

I/art : Explicit concurrent mark sweep GC freed 104710(7MB) AllocSpace objects, 21(416KB) LOS objects, 33% free, 25MB/38MB, paused 1.230ms total 67.216ms

原因

Concurrent:不会暂停应用线程的并发垃圾回收

Alloc:在堆已满时尝试分配内存引起的垃圾回收

Explicit:调用gc()产生的垃圾回收。

NativeAlloc:Native层出现的内存回收,如位图或RenderScript分配对象

CollectorTransition:堆转换引起的回收

HomogeneousSpaceCompact:空间压缩,减少RAM使用量并对堆进行碎片整理。

DisableMovingGc

HeapTrim

名称

Concurrent mark sweep (CMS):会释放和回收映像空间以外的所有其他空间

Concurrent partial mark sweep:会回收除了映像空间和 zygote 空间以外的所有其他空间。

Concurrent sticky mark sweep:只释放上次垃圾回收之后分配的对象,次垃圾回收比完整或部分垃圾清除运行的更频繁,因为更快速且暂停时间更短。

Marksweep + semispace:对堆进行碎片整理

释放的对象

此次垃圾回收从非大型对象空间回收的对象数量

释放的大小

此次垃圾回收从非大型空间回收的字节数量

释放的大型对象

此次垃圾回收从大型对象空间回收的对象数量

释放的大型对象大小

此次垃圾回收从大型对象空间回收的字节数量

堆统计数据

空闲百分比 (活动对象数量)/ (堆总大小)

暂停时间

通常情况下,暂停时间与垃圾回收运行时修改的对象引用数量成正比。

扩展阅读

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值