性能问题分析方法[1] --- RAM

性能问题分析方法(1) — RAM

这里主要是为了让新的同学可以快速的了解如何处理相关性能问题,性能问题繁琐,难度不大,一般建议给到新人处理,此处是主要说的是方法和案例的分析思路。

1. RAM内存占用导致的问题

一般越是大的内存的手机这个问题出现概率越小,越是低RAM的手机越要做的极致。

怎么确定这个就是内存导致的问题呢:

1)先用adb shell top (或者adb shell dumpsys cpuinfo其实是差不多的,只是dumpsys cpuinfo默认不是实时更新,我们也调整过让其更新)

=> 查看kswapd0、exe_cq、lmkd进程CPU占用是否比较高,如果比较高一般都是内存压力导致的卡顿问题,主要优化方向可以从缓解内存压力方向着手

    //我们一般看的是这个
    11% 133/kswapd0: 0% user + 11% kernel

    //exc_cq这个是mtk特有的,跟mtk的cq 功能有一定关系CONFIG_MTK_EMMC_CQ_SUPPORT
    19% 295/exe_cq/0: 0% user + 19% kernel

    //这个在打开system/core的lmkd才会出现,类似psi会导致这个进程的cpu占用较高
    lmkd
  1. 使用adb shell dumpsys -t 100 meminfo导出手机的基本memory的概况,类似输出是下面的内容
	Total PSS by OOM adjustment:
	    192,106K: Native
	         28,928K: surfaceflinger (pid 607)161,042K: System
	        161,042K: system (pid 1331)
	    131,415K: Persistent
	         91,176K: com.android.systemui (pid 1646 / activities)
	         25,890K: com.android.phone (pid 2473)
	   …
	Total RAM:   889,176K (status critical)
	Free RAM:   160,668K (        0K cached pss +   127,568K cached kernel +    33,100K free)
	Used RAM:   995,795K (  847,915K used pss +   147,880K kernel)
	Lost RAM:    42,742K
	     ZRAM:   170,564K physical used for   515,240K in swap (  786,428K total swap)

我们一般先看进程memory用量比较大的,还有最后的Free RAM和ZRAM

先介绍一下Free RAM:
Free RAM: 160,668K ( 0K cached pss + 127,568K cached kernel + 33,100K free)

=>如果cached pss为0,那么代表手机进入低内存(event log会出现am_low_memory,这个就不用再次猜测,内存是主因);

=> cached kernel这个属于kernel的缓存,一般系统kill掉进程后很大一部分会掉落到cached kernel里面去,cached kernel 实际主要是active file + inacive file的page 量,shrink 是顺序的回收流程, 如果前面已经shrink 操作如LMK 已经回收到memory 就不会走到file system 这边进行swap or active file 转 inactive , inactive switch 操作.(之前也遇到这个较大出现的问题项目,cached kernel可以到1.7G(该项目total ram是4G),修改方法就是调整lmk的策略,让其有机会跑到file system的回收。不过注意如果这个值很小也可能是一个问题,代表file system根本没有回收空间,内存压力大的时候不能从这里取得内存)

=> free这个小内存手机一般都比较小,这个在节点/proc/meminfo读出相应的值,如MemFree: 83044 kB,是系统真正free的memory。

如果出现上面问题该如何继续下去?
=> 首先我们看是native的process还是java的process,这2种调试方法不太一样

2. Native process的内存调试方法

1、使用adb shell dumpsys -t 100 meminfo +pid查看一下该进程的内存用量分布,如surfaceflinger优化前内存用量信息如下,surfacefinger内存用量有40多M,其中大部分增量在native heap(对比正常的monkey前)

	Applications Memory Usage (in Kilobytes):
	Uptime: 197500108 Realtime: 199595562
	                   Pss  Private  Private  SwapPss     Heap     Heap     Heap
	                 Total    Dirty    Clean    Dirty     Size    Alloc     Free
	                ------   ------   ------   ------   ------   ------   ------
	  Native Heap    11880    11880        0    12860        0        0        0
	  Dalvik Heap        0        0        0        0        0        0        0
	        Stack       16       16        0       40                           
	       Ashmem       44        0        0        0                           
	      Gfx dev     2744     2744        0        0                           
	    Other dev        8        0        8        0                           
	     .so mmap     1277      272      744     1160                           
	   Other mmap       17        8        8       16                           
	   EGL mtrack    16836    16836        0        0                           
	    GL mtrack      636      636        0        0                           
	      Unknown      220      220        0      492                           
	        TOTAL    48246    32612      760    14568        0        0        0

2、使用adb shell showmap +pid导出内存地址里面的映射表,然后排序看一下哪些是异常的,如此处较大的是libc_malloc自己申请的内存,还有就是kgsl-3d0(gpu相关的内存),我们主要看libc_malloc

	   27136    11880    11880        0        0        0    11880    12860    12860    4 [anon:libc_malloc]
	    4144     2744     2744        0        0        0     2744        0        0  184 /dev/kgsl-3d0

3、针对libc_malloc不管是google还是平台上都有提供相应调试方式,此处介绍的是google默认的调试方式

	1. $adb root

	2. $adb shell setenforce 0
	//同时此处加上将/data/local/tmp的权限改成777
	adb shell
	cd /data/local/
	chmod 777 tmp

	3. $adb shell setprop libc.debug.malloc.program audioserver

    //(如果这个设置不成功,可以adb shell, 进去设置)
	4. $adb shell setprop libc.debug.malloc.options "backtrace_enable_on_signal leak_track"

	5. $adb shell

	6. #ps -Af|grep audioserver

    //让进程重启,这样malloc_debug才能生效
	7. #kill -9 [halserver_pid]

    //此处指令是可以开始监控了native进程audioserver的用量了
	8. #kill -45 [new_halserver_pid]

	9. 此时你可以去复现问题

    //如果问题复现,可以输入这个指令,将在/data/local/tmp目录生成类似改进程堆栈信息的文件
	10. #kill -47 [new_halserver_pid] 

    //(native_heapdump_viewer是在development/scripts里面,这个操作需要复现问题手机的symbols)
	11. python native_heapdump_viewer.py --verbose --html backtrace_heap.2225.txt --symbols ***/out/target/product/***/symbols > backtrace_heap.html

4、用chrome打开相应的html文件,此处可以发现SurfaceFlinger.cpp:3476会导致大概2.6M的内存占用,这里就需要继续看模块代码才能处理了。(ps:此处可以发现20多M只导出5M,这个工具有部分缺陷,很多内容没有解析出来,有兴趣的同学可以自己研究一下如何解析出更多的内容,需要修改代码)

	0 0.00% 0 app
	5227414 100.00% 61363 zygote
	    5088172 97.34% 60778 libc++.so operator new(unsigned int) external/libcxxabi/src/stdlib_new_delete.cpp:32
	        2668176 51.04% 29258 libsurfaceflinger.so std::__1::__libcpp_allocate(unsigned int, unsigned int) external/libcxx/include/new:239
	            2635536 50.42% 28643 libsurfaceflinger.so android::SurfaceFlinger::commitTransaction() frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp:3476
	                2635536 50.42% 28643 libutils.so android::Looper::pollInner(int) system/core/libutils/Looper.cpp:323
	                    2635536 50.42% 28643 libutils.so android::Looper::pollOnce(int, int*, int*, void**) system/core/libutils/Looper.cpp:205
	                        2635536 50.42% 28643 libsurfaceflinger.so android::Looper::pollOnce(int) system/core/libutils/include/utils/Looper.h:267
	                            2635536 50.42% 28643 libsurfaceflinger.so android::SurfaceFlinger::waitForEvent() frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp:1532
	                                2635536 50.42% 28643 surfaceflinger main frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp:120
	                                    2635536 50.42% 28643 libc.so __libc_init bionic/libc/bionic/libc_init_dynamic.cpp:136
	                                        2635536 50.42% 28643 surfaceflinger _start_main bionic/libc/arch-common/bionic/crtbegin.c:45
	            32640 0.62% 615 libsurfaceflinger.so operator() frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp:2333
	                32640 0.62% 615 libsurfaceflinger.so std::__1::__function::__value_func<void (android::Layer*)>::operator()(android::Layer*&&) const external/libcxx/include/functional:1799


5、该问题修改的地方,从对应行号,其实可以知道SurfaceFlinger的recordBufferingStats导致的内存用量增加,至于修改方法,可以设置一个保存的数量或者干脆就不保存了,这个历史数据对用户影响不大。(这个现象目前在Google default android Q/R上应该还是存在的)


	void SurfaceFlinger::commitTransaction()
	{
	  if (!mLayersPendingRemoval.isEmpty()) {
	      for (const auto& l : mLayersPendingRemoval) {
                  //主要是这段逻辑引入的内存占用
	              recordBufferingStats(l->getName().string(),
	                      l->getOccupancyHistory(true));

3. 显示端的内存调试

mtk的自己做的节点
adb shell cat /sys/kernel/debug/ion/ion_mm_heap

高通的
adb shell cat /sys/kernel/debug/ion/heaps/system

上述主要看的是gpu显示相关或者surfacefinger的内存用量问题

=> 如android 7.0 mtk的6737出现surfacefinger普遍偏大,原因是surfacefinger的buffer设置较大,缓存了10个,后面是改成3个

	//6737平台上验证,进入播放视频,退出播放,重复几十次,
	//没有该问题,surfaceflinger用量一直维持在20多M,该6.0平台稳定性比7.0要好很多(指的是内存用量这块)。
	
	tmp/log$ adb shell cat /sys/kernel/debug/ion/ion_mm_heap | grep "280" 
	surfaceflinger( DpIonHandler) 280 1966080 0xd52a7a00 
	surfaceflinger( gralloc) 280 21319680 0xd757aa00 0xc35f4c80 4898816 0 2 1 0 1200000 0 0 280 
	surfaceflinger 0x0 0x0 0x0 0x0 p:1254 c:280 sf_info(-18771955 47 96 720 1280 0 0 720 1280 67045377 0 0 0 0 0 0 ) 0xc5ff1000 278528 0 3 2 0 6700000 0 0 280 
	surfaceflinger 0x0 0x0 0x0 0x0 p:1254 c:280 sf_info(-18771955 0 0 720 93 0 1187 720 93 134154241 0 0 0 0 1 0 ) 0xc7b78b40 139264 0 3 2 0 1e00000 0 0 280 
	surfaceflinger 0x0 0x0 0x0 0x0 p:1254 c:280 sf_info(-18771955 0 0 720 48 0 0 720 48 134154241 0 0 0 0 0 0 ) 0xc8733280 278528 0 3 2 0 2700000 0 0 280

=> Lost RAM比较大的问题

	//初步定位是media模块导致的内存泄漏
	          client              pid             size
	----------------------------------------------------
	 omx@1.0-service              823        134221824     //134M
	 omx@1.0-service              823        134221824

这个节点很有作用

4 Java process导致的内存泄漏

Java process内存分析手段目前比以前完善多了,以前使用的是hprof+MAT分析(大部分只能分析Dalvik虚拟机部分,Native信息较少),而Android studio可以使用profile进行memory的分析

4.1 MAT分析

先介绍mat工具吧(仅仅能分析java虚拟机的用量,一般对应下面2列内容)


	 Dalvik Heap    21302    21268        0      316    28662    16379    12283
	 Dalvik Other     2779     2776        0      100

=> 使用ddms或者monitor,点击dump hprof文件,即可导出java虚拟机的内存分布
在这里插入图片描述

=> 接着用MAT工具打开,选择Dominator Tree,查看java虚拟机树形的内存用量
在这里插入图片描述

=> 进去从最大的内存用量开始看,如此处是严格模式里面的数据,接下来需要看代码,最后发现这里大部分只在userdebug出现,在user版本也可能出现,概率会低一点,最终在项目上考虑还是给最大记录(循环记录)个数限定成1000(209,084个数的时候有4M, 可以找实际用户手机看一下这个是有多少量级,在用一个循环记录最新的数据即可)
在这里插入图片描述
在这里插入图片描述

Ps:这个一般还会使用list object或者show object by class查看一下incomingoutgoing的引用(篇幅有限,工具较旧,不多讲,后续有问题可以问)

4.2 Android Studio的Profile分析

android studio的Profile工具,这个比较强大(可以去除java虚拟机的内存占用,和部分跟虚拟机引用相关的native内存占用)

=> View –> tools window -> profile,然后选择+号(如红色部分),现在需要调试的手机和进程,后面会自动导出相关profile日志
在这里插入图片描述

=>如Android Q的system server内存用量高会出现PendingIntendRemoteCallback的内存占用比较高的问题,可以从hprof里面看到,然后就是找代码调试,此处也稍微介绍一下调试过程
在这里插入图片描述

=>使用断点,调试PendingIntend导致的RemoteCallbackmCallbacks比较多,如下是102374个(10多万条)数据,查看代码此处也可以使用adb shell dumpsys activity intents查看里面的PendingIntend$1的个数,找出地方,后面就是看代码逻辑看看如何修复这个问题,这个问题主要是alarm设置闹钟时会register远端的回调RemoteCallback,但是移除闹钟时由于部分逻辑binder跨进程调用会有问题,导致泄漏,后面就需要比较枯燥的看代码找方案的时间。
在这里插入图片描述

=> RemoteCallback里面的问题,打印register和unregister等的调用栈时发现,只有注册没有接触注册的操作,注册前mCallbacks.size()是1,注册后还是1,可能存在问题,后面就是断点,发现这部分逻辑存在问题,虽然new的一个新的对象,但是binder的对象是一致的,这就导致了jni的内存泄漏,这个问题比较隐蔽。

	Line 12032: 01-01 02:15:35.202  1350  1786 E RemoteCallbackList: yun_hen 21_1 register mCallbacks.size() = 1, callback = android.app.IWallpaperManagerCallback$Stub$Proxy@9aa3b84, cookie = null, binder = android.os.BinderProxy@4eef6fb, cb = android.os.RemoteCallbackList$Callback@7b5bf6d, getCallingUid=10058, getCallingPid=1706, this = android.os.RemoteCallbackList@848eba2
	Line 14398: 01-01 02:16:37.922  1350  1041 E RemoteCallbackList: yun_hen 21_1 register mCallbacks.size() = 1, callback = android.app.IWallpaperManagerCallback$Stub$Proxy@c0c092b, cookie = null, binder = android.os.BinderProxy@4eef6fb, cb = android.os.RemoteCallbackList$Callback@e2d3188, getCallingUid=10058, getCallingPid=1706, this = android.os.RemoteCallbackList@848eba2

Ps:此类内存分析还有很多需要做,一般挑选比较大的做,如果是持续做的话,每个小点也需要优化(主要是投入产出比)。
RemoteCallback在Android R和比较新的Android Q Google有提供patch,内部修改方案和Google类似,如果需要查看Google的修改,可以查看:2019-8 Remove cancel listeners from pending intent alarms
至于PendingIntend的问题,分析过程也是类似,Google 2019-11也有修复方案Remove cancel listeners from pending intent alarms
内部在Google的方案出来之前就已经修复这几个问题。

    // google工程师在2019.08.01的时候合入android主线(看时间算早了,好几个类似的问题都是在11月才传入主线),
    // 不过就算是2019.08.01也已经是正式版本是否之后好久了,而且一般厂家在pre-release的时候就会开始开发
	Author: Dan Zhang <danielzhang@google.com>  2019-08-01 13:19:30
	Committer: android-build-merger <android-build-merger@google.com>  2019-08-01 13:19:30
	Parent: 24ec321bf3bd094c5975439bd8285272f91dd655 (Add @UnsupportedAppUsage annotations)
	Parent: d40b5cecfefc7193732f17ca915ad2d48b4fc30b (Fix the reference leak on RemoteCallbackList)
	Child:  afdb23ab6f909c5438fa69aad458a11497cff216 (Use new UnsupportedAppUsage annotation.)

    Merge "Fix the reference leak on RemoteCallbackList"
    am: be30d27a8a
    
    Change-Id: Ibf79be3f125ab58c8048c15f3f6f3a3e693295e7

    // sony工程师在2019.04.22的修复了这个问题
	commit d40b5cecfefc7193732f17ca915ad2d48b4fc30b
	Author: Kyeongkab.Nam <Kyeongkab.Nam@sony.com>
	Date:   Mon Apr 22 18:14:45 2019 +0900
	
	    Fix the reference leak on RemoteCallbackList
	    
	    In case that register is invoked consecutively with same callback,
	    reference leack could be happened since unlinkToDeath for all
	    callbacks is not being called.
	    
	    Test: call register multiple times with same callback and unregister
	    callback same times. confirm the global reference table information.
	    
	    Change-Id: I7dbf108ea87b3ee7ce1e1a0ff75e05e8c4478f67
	
	diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java
	index b13e68d..0c3f291 100644
	--- a/core/java/android/os/RemoteCallbackList.java
	+++ b/core/java/android/os/RemoteCallbackList.java
	@@ -123,6 +123,7 @@ public class RemoteCallbackList<E extends IInterface> {
	             IBinder binder = callback.asBinder();
	             try {
	                 Callback cb = new Callback(callback, cookie);
	+                unregister(callback);
	                 binder.linkToDeath(cb, 0);
	                 mCallbacks.put(binder, cb);
	                 return true;

一般大的厂家这类问题都会有自己的修复方案(但从各个厂家的做法看,他们不一定会将类似问题反馈给Google),Google其实也会给在后面版本修复(不过这个时候比较晚了,大部分项目都已经出货了,如果厂家不进行优化,类似问题就会流入用户手中),这里其实就是技术壁垒的一部分,我有你没有,那不就是有优化的就有优势。

4.3 java native分析

最后再来看一下java native用量的调试方式,这个我们也是使用的是上面native进程用量的调试方式,注意此处也只能找出show maps中libc_malloc的用量


	  Native Heap     4155     4136        0     9521    15540    13099     2440

=>使用方法和上面类似,只是调试的进程都换成了app_process或者app_process64,这个是由于java进程都是zygote/zygote64 fork出来的。
Ps: 根据手机卡顿程度可以自己调整adb shell setprop libc.debug.malloc.options backtrace=64堆栈个数大小,如go的版本(adb shell setprop libc.debug.malloc.options backtrace=6 //go手机改小一点)


	adb root
	adb shell setenforce 0
	adb shell
	cd /data/local/
	chmod 777 tmp
	//如果是64位后面app_process换成app_process64
	setprop libc.debug.malloc.program app_process
	setprop libc.debug.malloc.options "backtrace_enable_on_signal backtrace leak_track"
	stop
	start
	ps -A | grep system_server kill -45 <pid of system_server>
	[Now you can reproduce the memory leak issue, after issue appeared, you can go to the next step
	to generate the memory leak backtrace. ]
	kill -47 <pid of system_server>
	[After a 'malloc/new/free' function triggered in 'system_server' at this time, you'll find memory dump
	logs under the path: /data/local/tmp/ now. ]


=> 这里也提供一个systemui的native用量的例子吧,我们知道是bitmap,可以在代码中打印调用bitmap的java堆栈(此处native的堆栈只到c++,java的堆栈需要自己加代码),后面发现是壁纸的bitmap,接下去就是找方案让bitmap不用的时候recycle


	//使用浏览器打开,看到:这个10MB是allocateHeapBitmap申请的,需要释放,但是释放时机太慢,开机5分钟内都可能没有释放
	17495249 100.00% 21898 app
	1.	11322709 64.72% 85 libhwui.so android::allocateHeapBitmap(unsigned int, SkImageInfo const&, unsigned int) frameworks/base/libs/hwui/hwui/Bitmap.cpp:80
	1.	11294997 64.56% 80 libhwui.so android::allocateBitmap(SkBitmap*, sk_sp<android::Bitmap> (*)(unsigned int, SkImageInfo const&, unsigned int)) frameworks/base/libs/hwui/hwui/Bitmap.cpp:68
	1.	11294997 64.56% 80 libhwui.so android::Bitmap::allocateHeapBitmap(SkBitmap*) frameworks/base/libs/hwui/hwui/Bitmap.cpp:92
	1.	11212052 64.09% 78 libandroid_runtime.so HeapAllocator::allocPixelRef(SkBitmap*) frameworks/base/core/jni/android/graphics/Graphics.cpp:611
	1.	11212052 64.09% 78 libskia.so SkBitmap::tryAllocPixels(SkBitmap::Allocator*) external/skia/src/core/SkBitmap.cpp:239
	1.	11212052 64.09% 78 libandroid_runtime.so doDecode(_JNIEnv*, SkStreamRewindable*, _jobject*, _jobject*) frameworks/base/core/jni/android/graphics/BitmapFactory.cpp:407
	10368000 59.26% 1 libandroid_runtime.so nativeDecodeFileDescriptor(_JNIEnv*, _jobject*, _jobject*, _jobject*, _jobject*)

4.4 binder分析

1、之前项目有个比较疑难的问题,看到system的Dalvik Heap用量增加,大概有55M左右


	** MEMINFO in pid 1302 [system] **
	                   Pss  Private  Private  SwapPss     Heap     Heap     Heap
	                 Total    Dirty    Clean    Dirty     Size    Alloc     Free
	                ------   ------   ------   ------   ------   ------   ------
	  Native Heap     5389     5352        0    16772    23612    21571     2040
	  Dalvik Heap    19638    19612        0    36407    62336    37760    24576
	        TOTAL   133272    40872    16004    69510    85948    59331    26616

2、用MAT打开,这里是5个线程在不停的内存泄漏,5+3+3+3+1 = 15M到16M左右(1个int数组,4个float数组)
在这里插入图片描述

这里的第一个难点是怎么知道thread是谁?最初的想法是在所有thread new的地方都打印堆栈(如果是native的thread或者基类的thread或者线程池,这样就比较麻烦)

3、接下去
例如要找MAT的java.lang.Thread @ 0x1757ba58


Class Name                          | Shallow Heap | Retained Heap | Percentage
--------------------------------------------------------------------------------
java.lang.Thread @ 0x1757ba58 Thread|          120 |     5,259,016 |     10.66%
--------------------------------------------------------------------------------

=>可以在profile中打开,找对thread这个类(这里只有62个),接下去根据地址排序,找到0x1757ba58地址的Thread,然后看到名字是HwBinder:1302_4
在这里插入图片描述

4、我们知道是HwBinder了,接下去需要看一下Binder传递的数据是什么先,可以使用MAT的Winow->Inspector

=> 可以看到这个线程里面的部分元素,如下,从mat里面的4个元素对应的数据是1.57542..0E9(E9是10的9次方),float[10]第四个都是0,
(注意这个float[10]在mat上是56个字节,但是在android studio float[10]是 40个字节,所以总量可能稍有差异,android studio上看到的是float 8.2+ int 4.7M大概13M左右)
在这里插入图片描述

5、那么需要查看binder对端,由于这个是android Q go项目没有system trace,那么可以查看“/sys/kernel/debug/binder”这个节点的日志,每个1s打印出来,过滤与system_server通信的binder


	adb shell cat "/sys/kernel/debug/binder/failed_transaction_log"
	adb shell cat "/sys/kernel/debug/binder/transaction_log"
	adb shell cat "/sys/kernel/debug/binder/transactions"
	adb shell cat "/sys/kernel/debug/binder/stats"
	adb shell cat "/sys/kernel/debug/binder/state"

=>可以看到gnss的gps模块和suspend这个存在与HwBinder通信,接下去就看代码,如查看“frameworks/base/services/core/jni”、“frameworks/base/core/jni”两个jni文件中的代码,这个数据应该是有往上传的(binder通信数据一般都2端都有)


    //
	716:    outgoing transaction 98649452: c2fa4380 from 577:691 to 1393:2153 code e flags 10 pri 0:120 r1
	adb shell ps | grep "577"
	gps            577     1   38212   2160 binder_thread_read  0 S android.hardware.gnss@2.0-service-qti
	
	19040:99854269: reply from 571:571 to 1393:2573 context hwbinder node 0 handle -1 size 28:8 ret 0/0 l=0
	system         571     1   16512   1760 binder_thread_read  0 S android.system.suspend@1.0-service

=>接着查到com_android_server_location_GnssLocationProvider.cpp的gnssSvStatusCbImpl比较可疑(数据结构和类型惊人的相似)

	
	//frameworks/base/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
	675  Return<void> GnssCallback::gnssSvStatusCbImpl(const T& svStatus) {
	676      JNIEnv* env = getJniEnv();
	677  
	678      uint32_t listSize = getGnssSvInfoListSize(svStatus);
	679      if (listSize > static_cast<uint32_t>(
	680              android::hardware::gnss::V1_0::GnssMax::SVS_COUNT)) {
	681          ALOGD("Too many satellites %u. Clamps to %u.", listSize,
	682                static_cast<uint32_t>(android::hardware::gnss::V1_0::GnssMax::SVS_COUNT));
	683          listSize = static_cast<uint32_t>(android::hardware::gnss::V1_0::GnssMax::SVS_COUNT);
	684      }
	685      //1个int数组,4个float数组
	686      jintArray svidWithFlagArray = env->NewIntArray(listSize);
	687      jfloatArray cn0Array = env->NewFloatArray(listSize);
	688      jfloatArray elevArray = env->NewFloatArray(listSize);
	689      jfloatArray azimArray = env->NewFloatArray(listSize);
	690      jfloatArray carrierFreqArray = env->NewFloatArray(listSize);
	691  
	692      jint* svidWithFlags = env->GetIntArrayElements(svidWithFlagArray, 0);
	693      jfloat* cn0s = env->GetFloatArrayElements(cn0Array, 0);
	694      jfloat* elev = env->GetFloatArrayElements(elevArray, 0);
	695      jfloat* azim = env->GetFloatArrayElements(azimArray, 0);
	696      jfloat* carrierFreq = env->GetFloatArrayElements(carrierFreqArray, 0);

6、=>对端是GnssLocationProvider.java的reportSvStatus,此处可以设置断点


    //frameworks/base/services/core/java/com/android/server/location/GnssLocationProvider.java
    private void reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0s,
            float[] svElevations, float[] svAzimuths, float[] svCarrierFreqs) {
        SvStatusInfo svStatusInfo = new SvStatusInfo();
        svStatusInfo.mSvCount = svCount;
        svStatusInfo.mSvidWithFlags = svidWithFlags;
        svStatusInfo.mCn0s = cn0s;
        svStatusInfo.mSvElevations = svElevations;
        svStatusInfo.mSvAzimuths = svAzimuths;
        svStatusInfo.mSvCarrierFreqs = svCarrierFreqs;

        sendMessage(REPORT_SV_STATUS, 0, svStatusInfo);
    }

=>发现传递的值中一个也是很大的值1.5*10的9次方
可以基本确定这类型的数据就是gps的模块产生的
在这里插入图片描述

=>当然也可以用lldb断点c++的地方,此处可以看到虽然这个是c++代码,但是调用地方是javaThreadShell这个是java的thread,所以算在java上了


	//frameworks/base/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
	 (lldb) bt
	* thread #25, name = 'HwBinder:1276_1', stop reason = breakpoint 1.1
	  * frame #0: 0x7e41f1b4 libandroid_servers.so`android::hardware::Return<void> android::GnssCallback::gnssSvStatusCbImpl<android::hardware::hidl_vec<android::hardware::gnss::V2_0::IGnssCallback::GnssSvInfo> >(android::hardware::hidl_vec<android::hardware::gnss::V2_0::IGnssCallback::GnssSvInfo> const&)
	    frame #1: 0x7e418dba libandroid_servers.so
	    frame #2: 0x7dce4328 android.hardware.gnss@2.0.so`android::hardware::gnss::V2_0::BnHwGnssCallback::_hidl_gnssSvStatusCb_2_0(android::hidl::base::V1_0::BnHwBase*, android::hardware::Parcel const&, android::hardware::Parcel*, std::__1::function<void (android::hardware::Parcel&)>) + 172 
	    frame #3: 0x7dce48de android.hardware.gnss@2.0.so`android::hardware::gnss::V2_0::BnHwGnssCallback::-OnTransact(unsigned int, android::hardware::Parcel const&, android::hardware::Parcel*, unsigned int, std::__1::function<void (android::hardware::Parcel&)>) + 814
	    frame #4: 0xa3d744fc libhidlbase.so`android::hardware::BHwBinder::transact(unsigned int, android::hardware::Parcel const&, android::hardware::Parcel*, unsigned int, std::__1::function<void (android::hardware::Parcel&)>) + 48
	    frame #5: 0xa3d76b2c libhidlbase.so`android::hardware::IPCThreadState::getAndExecuteCommand() + 968 
	    frame #6: 0xa3d77a48 libhidlbase.so`android::hardware::IPCThreadState::joinThreadPool(bool) + 68 
	    frame #7: 0xa3d82cfc libhidlbase.so 
	    frame #8: 0xa44508c4 libutils.so`android::Thread::_threadLoop(void*) + 216 
	    frame #9: 0xa5b10d16 libandroid_runtime.so`android::AndroidRuntime::javaThreadShell(void*) + 86 
	    frame #10: 0xa54708d8 libc.so`__pthread_start(void*) + 22 
	frame #11: 0xa542a130 libc.so`__start_thread + 32

7、最后就是看代码,确实是jni中new了没有delete

//frameworks/base/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
    jintArray svidWithFlagArray = env->NewIntArray(listSize);
    jfloatArray cn0Array = env->NewFloatArray(listSize);
    jfloatArray elevArray = env->NewFloatArray(listSize);
    jfloatArray azimArray = env->NewFloatArray(listSize);
    jfloatArray carrierFreqArray = env->NewFloatArray(listSize);

    jint* svidWithFlags = env->GetIntArrayElements(svidWithFlagArray, 0);
    jfloat* cn0s = env->GetFloatArrayElements(cn0Array, 0);
    jfloat* elev = env->GetFloatArrayElements(elevArray, 0);
    jfloat* azim = env->GetFloatArrayElements(azimArray, 0);
    jfloat* carrierFreq = env->GetFloatArrayElements(carrierFreqArray, 0);

    env->ReleaseIntArrayElements(svidWithFlagArray, svidWithFlags, 0);
    env->ReleaseFloatArrayElements(cn0Array, cn0s, 0);
    env->ReleaseFloatArrayElements(elevArray, elev, 0);
    env->ReleaseFloatArrayElements(azimArray, azim, 0);
    env->ReleaseFloatArrayElements(carrierFreqArray, carrierFreq, 0);

    //Fix memory leakage
    env->DeleteLocalRef(svidWithFlagArray);
    env->DeleteLocalRef(cn0Array);
    env->DeleteLocalRef(elevArray);
    env->DeleteLocalRef(azimArray);
    env->DeleteLocalRef(carrierFreqArray);

//NewIntArray/NewFloatArray需要和DeleteLocalRef配套使用,GetIntArrayElements/GetFloatArrayElementsReleaseIntArrayElements/ReleaseFloatArrayElements也需要配套使用,c++不像java会自动释放本地变量,所以这里需要非常注意

4.5 其它调试方法

1、 我们发现除了native和Dalvik的用量,还有so、apk、EGL/GL等的用量,这部分我们怎么看呢


	** MEMINFO in pid 1393 [system] **
	                   Pss  Private  Private  SwapPss     Heap     Heap     Heap
	                 Total    Dirty    Clean    Dirty     Size    Alloc     Free
	                ------   ------   ------   ------   ------   ------   ------
	  Native Heap     6813     6784        0     4316    12992    10725     2266   
	  Dalvik Heap    16036    15996        0      204    26694    15254    11440  
	 Dalvik Other     2450     2448        0       60            
	        Stack       24       24        0       16                           
	       Ashmem       30       24        0        0                           
	      Gfx dev      852      204      648        0                           
	    Other dev       39       20       12        0                           
	     .so mmap     2436      308      892      835                           
	    .jar mmap     7861        0     6708        0                           
	    .apk mmap    10159        0     6752        0                           
	    .ttf mmap       44        0        0        0                           
	    .dex mmap     5417      116     5300      128                           
	    .oat mmap     2426        0     1388        0                           
	    .art mmap     8365     7568       16     2976                           
	   Other mmap     1621     1428       12        0                           
	   EGL mtrack     1944     1944        0        0                           
	    GL mtrack     1428     1428        0        0                           
	      Unknown     2102     2100        0     1500                           
	        TOTAL    80082    40392    21728    10035    39686    25979    13706

2、先看一堆mmap的用量,这个可以使用showmap查找一下,如下是system server的map堆栈信息,可以看到services.odex、Velvet.apk、boot-framework.art其实都是载入system server里面了.(这里部分是有优化空间的,如之前项目针对systemui等优化过调用camera的context进程上下文导致camera apk载入了systemui)
在这里插入图片描述

3、EGL/GL的占用

上面有介绍过,一般用的也是下面2个节点去查看,这部分一般都是平台商gpu的部分,不一定看得到代码.

	// mtk的自己做的节点
	adb shell cat /sys/kernel/debug/ion/ion_mm_heap
	// 高通的
	adb shell cat /sys/kernel/debug/ion/heaps/system
	adb shell cat /sys/kernel/debug/dma_buf/dmaprocs           // kernel 4.14以后的版本使用这个

这个节点可以定位大部分的问题,如Android R的TaskSnapshot会导致ion增加较大,可以通过这个节点,辅助systrace分析载入逻辑,找到TaskSnapshot进行优化

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值