皮皮网

【谷歌spring源码分析】【mdb驱动源码】【kd tree源码】anr源码

2024-11-20 01:24:46 来源:期货资金盘源码

1.anrԴ??
2.了解android的framework层对工作有什么帮助吗?
3.Android N 四大组件的工作原理

anr源码

anrԴ??

       概述

       在线监控发现OOM涨幅较大,定位修复内存泄漏和大对象占用问题后,仍未能达到正常标准。在新上报的hprof文件中发现,几乎所有案例中都有名为FinalizerReference的对象,数量庞大,谷歌spring源码分析内存占用高居榜首,判断其为引起OOM上涨的主因。

       ReferenceQueue

       ReferenceQueue是一个存放Reference对象的队列,当Reference对象所引用的对象被GC回收时,该Reference对象会被加入到引用队列中。例如,创建一个bean强引用与一个reference软引用,当bean被回收时,软引用reference对象会被加入queue队列,开发者需自行处理。Leakcanary检测内存泄漏原理基于应用的mdb驱动源码ReferenceQueue引用队列,例如Activity的引用队列。

       FinalizerReference

       介绍Finalizer对象,指在其Java类中复写了finalize()方法且非空的对象,称作f类。类加载过程中会标记加载的Java类是否为f类。

       FinalizerReference概述

       FinalizerReference是协助FinalizerDaemon线程处理对象finalize()工作的工具。它通过FinalizerReference类创建链表,每个FinalizerReference对象使用ReferenceQueue创建,当对应对象Object referent被回收后,该FinalizerReference会放入ReferenceQueue。

       FinalizerReference.add

       FinalizerReference.add方法由虚拟机调用,创建对象时发现该类为f类,调用此方法创建FinalizerRefence对象并加入到头链表中。

       FinalizerReference.remove

       当f类对象发生GC时,其对应的FinalizerReference对象会被加入FinalizerReference.queue队列,remove时机与FinalizerDaemon守护线程相关。kd tree源码FinalizerDaemon.runInternal方法通过queue的poll/remove方法获取queue中的Reference引用,执行doFinalize方法调用Finalizer对象的finalize()方法。

       小结

       FinalizerReference主要协助FinalizerDaemon线程执行Finalizer对象的finalize()方法。

       ReferenceQueueDaemon

       FinalizerDaemon守护线程已介绍,这里再看ReferenceQueueDaemon守护线程。创建引用对象时可以关联一个ReferenceQueue队列,被引用对象被GC回收时,该reference对象会被加入其关联队列。加入队列操作由ReferenceQueueDaemon守护线程完成。

       FinalizerWatchdogDaemon

       补充FinalizerWatchdogDaemon守护线程,与FinalizerDaemon和ReferenceQueueDaemon线程一同启动。FinalizerDaemon和ReferenceQueueDaemon线程的runInternal方法中,monitoringNotNeeded方法休眠线程停止timeout计时,此方法唤醒FinalizerWatchdogDaemon守护线程。FinalizerWatchdogDaemon监控两种执行时长:FINALIZER_DAEMON和RQ_DAEMON,执行超时抛出TimeOutException异常,可用棋牌源码避免在finalize()方法中执行耗时操作。

       OOM排查

       排除大对象和内存泄漏后,在hprof中发现大量X(业务上的某个对象)堆积,X对象对应Java类与Native层有关,重写了finalize()方法,线下无法复现X对象堆积路径。可能的业务场景代码逻辑不当导致X对象疯狂创建,导致FinalizerDaemon线程回收不及时。通过显式调用系统gc和runFinalization方法,发现子线程调用无效,主线程调用导致ANR。查看ANR堆栈发现问题源于某个finalize()方法调用的Native代码卡死,逻辑问题导致死锁,阻塞FinalizerDaemon线程执行,引起对象堆积。

       总结

       Java中finalizer()实现了类似析构函数的cas client源码概念,可以在对象被回收前执行回收性操作。f类使用不当可能导致问题,避免重载finalizer()方法,通过逻辑接口释放内存,避免频繁创建或大型对象通过finalizer()释放,以防出现相关问题。

       相关守护线程有四个,可深入查看源码。

       线上监控时,可能还需优化UI渲染、奔溃、卡顿、体积包、网络、存储等,整理成脑图。

       内功修炼需持续不断,性能优化同样需要坚持。

了解android的framework层对工作有什么帮助吗?

       掌握Android框架层的知识对开发者来说至关重要。深入理解框架层,能让你在进行性能优化、监控应用状态、调用API等工作中更加得心应手。

       比如在监控应用性能时,了解掉帧、ANR(应用程序无响应)、启动监控等机制,需要对框架层有深入理解。这包括知道如何利用机制进行监控,选择正确的监控点,以及通过反射等技术实现监控。

       在调用API时,往往Android框架层已经为应用提供了丰富的接口,但如果对这些机制的原理了解不深,很难在此基础上进行优化。例如,在优化应用启动速度时,需要定制合适的StartingWindow,合理处理宽高、DelayLoad的时机,以及Service和Activity的启动策略。

       Handler、MessageQueue、Looper等概念,对Android开发者来说至关重要。通过源码深入理解这些机制,有助于更好地理解ThreadLocal、线程与Handler的关系,以及避免在子线程更新UI等常见问题。此外,ContentProvider、Broadcast、Service等组件如何利用Message进行ANR监控,也是深入学习的重点。

       进程管理机制同样值得深入研究。了解Android系统如何通过AMS(ActivityManagerService)对进程进行优先级设置和内存管理,可以提高应用的存活率。掌握这些机制有助于开发者优化资源分配,提升应用性能。

       在使用Activity启动模式时,除了熟练应用各种模式,了解Activity栈和Task的管理机制,能够帮助开发者更深入地理解启动模式的使用场景和限制。

       关于View的Hardware Layer,理解其实现机制对于优化动画性能至关重要。知道何时将View设置为硬件加速模式以及如何在动画前后切换,可以帮助开发者在不同场景下实现最佳性能。

       在处理卡顿和掉帧问题时,深入理解Choreographer、VSync、SurfaceFlinger、Binder等组件的工作原理,能够帮助开发者更全面地分析和解决性能问题。掌握这些知识有助于在不同场景下优化应用性能,特别是在高帧率渲染、低内存环境以及多线程通信等场景中。

       综上所述,深入学习Android框架层的知识,不仅能够提升开发者对现有技术的理解,还能够促进在性能优化、系统监控和API使用等方面取得突破。通过阅读源码,开发者可以更全面地掌握Android系统的内部运作机制,从而在实际开发中实现更高效、更稳定的应用。

Android N 四大组件的工作原理

       æœ¬æ–‡ä¾§é‡è®²è§£android N 系统中四大组件的工作原理,不同系统原理略有差别。通过分析四大组件的工作流程加深对Android Framework的理解,也为插件化开发打下基础。

        Activity

        展示一个界面并和用户交互,它扮演的是一个前台界面的角色。

        Service

        计算型组件,用于后台执行一系列计算任务,工作在主线程,耗时操作需要另起线程, 分为启动状态和绑定状态。

        BroadcastReceiver

        消息型组件,主要用于不同组件或者不同应用之间的消息传递,它工作在系统内部,不适合执行耗时操作,操作超过5s,会出现ANR。

        ContentProvider

        数据共享型组件,用于向其他组件或者应用共享数据,主要执行CURD操作。

        我们启动一个activity有两种方法,

        第一种(Activity直接启动方式):

        Intent intent = new Intent(this, MainActivity.class);

        startActivity(intent);

        第二种(Context启动方式)

        Intent intent = new Intent(this, MainActivity.class);

        getApplicationContext().startActivity(intent);

        不同的启动方式Activity的工作流程有点差别。

        两种启动都会调用到Instrumentation类中的execStartActivity的方法,系统最终是通过ActivityThread中的performLaunchActivity完成Activity的创建和启动。

        performLaunchActivity方法主要完成以下工作:

        1、通过ActivityClientRecord对象获取启动activity的组件信息

        2、通过mInstrumentation对象的newActivity方法调用classloader完成activity的创建

        3、通过r.packageInfo(LoadedApk 对象)的makeApplication方法尝试创建Application对象

        4、创建ContextImpl对象并调用Activity的attach方法完成一些数据的初始化

        5、调用Activity的onCreate方法

        在Activity启动的过程中,App进程会频繁地与AMS进程进行通信:

        App进程会委托AMS进程完成Activity生命周期的管理以及任务栈的管理;这个通信过程AMS是Server端,App进程通过持有AMS的client代理IActivityManager完成通信过程;

        AMS进程完成生命周期管理以及任务栈管理后,会把控制权交给App进程,让App进程完成Activity类对象的创建,以及生命周期回调;这个通信过程也是通过Binder完成的,App所在server端的Binder对象存在于ActivityThread的内部类ApplicationThread;AMS所在client通过持有IApplicationThread的代理对象完成对于App进程的通信。

        Service有两种启动方式,startService()和bindService(),两种状态可以并存:

        startService流程

        bindService流程

        BroadcastReceiver的工作过程主要包括广播的注册、发送和接收:

        动态注册过程:

        发送过程

        静态注册是由PackageManagerService(PMS)在应用安装的时候完成整个注册过程的,除广播以外,其他三大组件也都是在应用安装时由PMS解析并注册的。

        每个进程的入口都是ActivityThead.main(),App的启动流程如下:

        从源码中可以看出:

        应用启动的入口为ActivityThread的main方法,main方法会创建ActivityThread实例并创建主线程消息队列。

        attach方法中远程调用AMS的attachApplication方法,并提供ApplicationThread用于和AMS的通信。

        attachApplication方法会通过bindApplication方法和H来调回ActivityThread的handleBindApplication,这个方法会先创建Application,再加载ContentProvider,然后才会回调Application的onCreate方法。

        由上图可以看出,在ContentProvider的启动过程中伴随着app进程的启动。

        ContentProvider的其他CURD操作如insert,delete,update跟query的流程类似。