前言:
今天你们对“android内存管理机制面试”都比较关注,各位老铁们都想要知道一些“android内存管理机制面试”的相关内容。那么小编也在网络上搜集了一些有关“android内存管理机制面试””的相关资讯,希望看官们能喜欢,姐妹们一起来学习一下吧!内存泄露场景:
handler使用不当内存泄露。
静态变量持有Context 强引用 。
匿名内部类引起的内存泄露,最典型的例子就是Handler泄漏。
Stream io流,bitmap等使用后未关闭或者注销。
eventbus、广播等未关闭注册。
Android 中的 WebView 存在很大的兼容性问题,有些 WebView 甚至存在内存泄露的问题。所以通常根治这个问题的办法是为 WebView 开启另外一个进程,通过 AIDL 与主进程进行通信, WebView 所在的进程可以根据业务的需要选择合适的时机进行销毁,从而达到内存的完整释放。
讲讲LeakCanary 的原理?
作为一个内存检测泄露的工具框架。
LeakCanary实现内存泄漏的主要判断逻辑是这样的。当我们观察的Activity或者Fragment销毁时,我们会使用一个弱引用去包装当前销毁的Activity或者Fragment,并且将它与本地的一个ReferenceQueue队列关联。
在KeyedWeakReference内部,使用了key和name标识了一个被检测的WeakReference对象。在注释1处,将弱引用和引用队列 ReferenceQueue 关联起来,如果弱引用referent持有的对象被GC回收,JVM就会把这个弱引用加入到与之关联的引用队列referenceQueue中。即 KeyedWeakReference 持有的 Activity 对象如果被GC回收,该对象就会加入到引用队列 referenceQueue 中。
所以我们知道如果GC触发了,系统会将当前的引用对象存入队列中。
如果没有被回收,队列中则没有当前的引用对象。所以LeakCanary会去判断,ReferenceQueue是否有当前观察的Activity或者Fragment的引用对象,第一次判断如果不存在,就去手动触发一次GC,然后做第二次判断,如果还是不存在,则表明出现了内存泄漏。
事件分发流程:
核心的方法有三个: dispatchTouchEvent 、onInterceptTouchEvent 、 onTouchEvent
流程图如下:
在 Android 中,当用户在设备上触发一个操作时,比如点击屏幕或者按下物理键,这些操作将会产生一个事件,并且会被封装成一个 MotionEvent 或者 KeyEvent 对象。事件传递到 View 的过程如下:
事件产生:用户在设备上触发操作,事件被产生。事件传递:事件由activity传到Phonewindow到Decoreview在传递给顶层的 View 或 ViewGroup,也就是当前界面的根视图。事件分发:根视图调用 dispatchTouchEvent() 或者 dispatchKeyEvent() 方法将事件分发给对应的子 View 进行处理。事件处理:子 View 处理事件,如果事件被消费了,则返回 true,否则返回 false。事件传递:如果子 View 返回 false,则事件被传递给父 View 进行处理,重复步骤 3-4 直到事件被处理或者到达根视图。
如果事件最终被消费了,则该事件将不会继续传递到其它 View 进行处理,相反,如果事件未被消费,则它将传递给其它 View 进行处理。
当事件处理完成后,系统会将事件的处理结果返回给 Activity,具体流程如下:
Activity 的 onTouchEvent() 或者 onKeyDown() 方法会被调用。如果事件被消费了,则返回 true,否则返回 false。如果返回 true,表示该事件已经被处理了,不需要进一步处理。如果返回 false,事件将继续传递到 Activity 的父类进行处理,直到事件被消费或者到达了顶级父类。 Android 事件传递到 View 并返回给 Activity 的流程是由底层向上层递归处理的,直到找到一个能够处理该事件的 View,并且该 View 成功地消费了该事件,否则该事件将被传递给 Activity 进行处理。
问:Android中加载大图方案?
Android中加载大图有多种方案,以下是一些常用的方案:
更好的方案是在SubScaleSampleImageView中,将大图切片,再判断是否可见,如果可见则加入内存中,否则回收,减少了内存占用与抖动 同时根据不同的缩放比例选择合适的采样率,进一步减少内存占用 同时在子线程进行decodeRegion操作,解码成功后回调至主线程,减少UI卡顿.
使用BitmapRegionDecoder: BitmapRegionDecoder是Android SDK提供的一种用于解码局部区域的大图像的工具类。可以通过设置解码的区域来加载大图,从而避免一次性加载整张图片造成内存溢出的问题。使用缩略图: 可以先加载一个缩略图,当用户需要查看大图时,再通过异步加载的方式加载原图。这种方式可以避免一次性加载大图造成的卡顿问题。关键字“inSampleSize”
BitmapFactory.Options options = new BitmapFactory.Options();options.inSampleSize = 4; // 缩放比例,值越大,缩放比例越大,图片越小Bitmap thumbnail = BitmapFactory.decodeFile(filePath, options);imageView.setImageBitmap(thumbnail);使用Picasso、Glide等第三方库: 这些库能够有效地处理图片加载的问题,包括缓存、异步加载等功能,同时还支持网络图片加载等操作。
内存管理:Glide 对图片进行了内存管理,当加载超大图片时,它会将图片分成小块加载,而不是一次性将整个图片加载到内存中。这样可以避免内存溢出和应用程序崩溃的风险。
图片压缩:Glide 能够自动对图片进行压缩,减小图片的大小和分辨率,以降低对内存和性能的影响。这对于加载超大图片来说尤为重要,因为它们通常具有较高的像素密度和文件大小。
自定义View —— onMeasure、 onLayout布局过程的作用确定每个View的尺寸和位置作用:为绘制和触摸范围做支持绘制:知道往哪里了画触摸返回:知道用户点的是哪里布局的流程从整体看测量流程:从根 View 递归调用每一级子 View 的 measure 方法,对它们进行测量。布局流程:从根 View 递归调用每一级子 View 的 layout 方法,把测量过程得出的子 View 的位置和尺寸传给子 View,子 View 保存。从个体看
对于每一个 View:
运行前,开发者会根据自己的需求在 xml 文件中写下对于 View 大小的期望值在运行的时候,父 View 会在 onMeaure()中,根据开发者在 xml 中写的对子 View 的要求, 和自身的实际可用空间,得出对于子 View 的具体尺寸要求子 View 在自己的 onMeasure中,根据 xml 中指定的期望值和自身特点(指 View 的定义者在onMeasrue中的声明)算出自己的*期望
如果是 ViewGroup 还会在 onMeasure 中,调用每个子 View 的 measure () 进行测量.
父 View 在子 View 计算出期望尺寸后,得出⼦ View 的实际尺⼨和位置⼦ View 在自己的 layout() ⽅法中将父 View 传进来的实际尺寸和位置保存
如果是 ViewGroup,还会在 onLayout() ⾥调用每个字 View 的 layout() 把它们的尺寸 置传给它们启动优化:
主题设置透明并设置启动图片防止白屏。
onCreate异步线程。少做初始化工作。idleHandler做不重要工作。gc抑制和核心线程绑定大核。
mainActivity和splashActivity合并。
核心功能核心页面内容优先显示。其他使用viewstub。
odex延后加载。
Glide源码相关和图片优化相关:
多种图片格式的缓存,适用于更多的内容表现形式(如Gif、WebP、缩略图、Video)生命周期集成(根据Activity或者Fragment的生命周期管理图片加载请求)高效处理Bitmap(bitmap的复用和主动回收,减少系统回收压力)高效的缓存策略,灵活(Picasso只会缓存原始尺寸的图片,Glide缓存的是多种规格),加载速度快且内存开销小(默认Bitmap格式的不同,使得内存开销是Picasso的一半)glide 可优化gif图片加载。解码器替换为giflib,从Java层解码改为native层解码
kotlin相关
kotlin优势:
语法糖,空安全,代码简洁,可对string类拓展自定义方法,协程解决了代码回调地狱问题。
协程相关问题:
本质上还是对线程的封装的一套api,Java是开辟线程,协程是通过调度线程去实现方法的挂起和恢复。所以可以开启非常多的协程而不会崩溃。
suspend是一个提醒作用。提醒你需要把方法异步,放在协程体里面。
协程工作的核心就是它内部的状态机,invokeSuspend() 函数。
所以函数即便被 suspend 修饰了,但是也未必会挂起。需要里面的代码编译后有返回值为 COROUTINE_SUSPENDED 这样的标记位才可以,所以程序执行到 case 0 的时候就 return 了。那就意味着方法被暂停了,那么协程也被暂停了。所以说协成的挂起实际上是方法的挂起,方法的挂起本质是 return。
列表卡顿优化
图片在停止滑动后加载,
避免用大图片做背景。用shape做背景绘制。
使用TraceView 抓取日子后对总耗时排序,通过app的包名搜索关键字,定位到 耗时方法
google描述这2个函数对耗时是敏感的。
1 优化onBindViewHolder. 这个函数原来会根据从网络获取不同的状态,判断是否显示和隐藏背景,通过ImageView.setBackgroundResource()。
因为背景不是动态获取的,所以优化为默认在ImageView中显示,通过setVisibility显示和隐藏ImageView.
优化后再次抓取TraceView,滑动列表是会不断触发onBindViewHolder, 但耗时只有1ms左右。 显示应该避免setBackground这种耗时操作。
那如果你确实需要加载不同图片呢?可以使用Glide等图片加载框架,在快速滑动时显示默认图片,待停止滑动后,再加载显示图片图片。
3 固定高度,避免重复计算高度 RecyclerView.setHasFixedSize(true);
4,局部刷新列表item,或者使用工具类对比一下哪里需要刷新就刷新哪里。
海外上架相关经验:遵循上架政策,并兼容到30或者更高。
1.马甲包:混淆代码,加入垃圾代码(使用AndroidJunkCode插件生成)。
更换域名,icon,UI,包名,创建新应用。马甲包架构:利用路由(阿里的Arounter)进行组件化拆分,通过在buidl.gradle中去依赖UI模块进行功能组装。海外谷歌支付流程,防止掉单的几种方式。
回:主要是客户端回调问题,点击下单-》查询一遍有没有掉单-》去自己后台下单-》拉起google支付-》支付成功--》客户端回调--》回调给自己后端--》发货--》调用消耗商品操作--》完成支付流程。
防止掉单:客户端轮询查订单信息,在启动或者登录后再查一遍是否有掉单情况(有没有订单未消费)。
在安卓应用中,可以通过以下方面来做性能优化:
布局优化:减少布局层次结构、减少不必要的布局操作。绘图优化:避免在UI线程上执行耗时绘图操作、减少不必要的绘图操作。线程优化:合理使用线程,避免在UI线程上执行耗时操作,使用线程池避免线程创建和销毁的开销。内存优化:及时释放不需要的对象、合理使用内存缓存、避免内存泄漏等。网络优化:减少网络请求次数、使用缓存、使用合适的网络请求库等。数据库优化:合理使用数据库、优化查询、使用索引等。APK瘦身:减少APK包的大小,去掉不必要的资源、代码等。热修复:及时修复应用中的崩溃问题,提高应用的稳定性和用户体验。
在安卓开发中,有很多性能优化工具可供使用。以下是一些常见的性能优化工具:
Android Profiler:Android Studio 自带的工具,可以帮助开发者实时监控应用程序的 CPU、内存、网络和电池等方面的性能数据。Traceview:Android Studio 自带的工具,用于分析 Android 应用程序的性能数据,包括方法执行时间、调用堆栈等信息。Systrace:Android Studio 自带的工具,用于分析 Android 应用程序的系统跟踪信息,例如 CPU 使用率、内存使用率、I/O 操作等。LeakCanary:一个内存泄漏检测库,可以帮助开发者快速定位内存泄漏问题。AndroidLint:Android Studio 自带的静态代码分析工具,可以检测代码中的一些潜在问题,例如性能问题、安全问题等。Memory Profiler:Android Studio 自带的工具,用于分析应用程序的内存使用情况,包括内存泄漏问题、对象分配等。GPU 监视器:Android Studio 自带的工具,可以帮助开发者分析应用程序的 GPU 性能。Battery Historian:一个用于分析 Android 设备电池使用情况的工具,可以帮助开发者分析应用程序在电池寿命方面的影响。Lint:Android Studio 自带的工具,用于检测代码中的一些问题,例如未使用的资源、未使用的代码等。RenderDoc:一个用于分析应用程序的 GPU 渲染性能的工具,可以帮助开发者分析应用程序的渲染性能。
这些工具可以帮助开发者定位应用程序的性能问题,并提供相应的解决方案。但需要注意的是,这些工具只是辅助性的,最终的性能优化还需要开发者进行具体的代码实现。
下面是一些 Android 中内存优化的细节:
尽可能避免使用静态变量:静态变量会一直存在于内存中,直到应用程序关闭,这会占用大量的内存资源。因此,应尽可能避免使用静态变量,可以通过使用单例模式来避免使用静态变量。尽可能使用轻量级数据结构:轻量级数据结构,例如 SparseArray 和 ArrayMap 等,可以减少内存的使用,提高应用程序的性能。及时释放不再使用的资源:当应用程序不再使用资源时,应及时释放这些资源,以释放内存资源。避免频繁的创建和销毁对象:创建和销毁对象需要消耗大量的内存资源,因此,应尽量避免频繁的创建和销毁对象,可以通过使用对象池等技术来避免频繁的创建和销毁对象。使用 Bitmap 缩放:在加载大图像时,可以通过 Bitmap 缩放技术来减少内存的使用,提高应用程序的性能。使用软引用或弱引用:软引用和弱引用可以帮助应用程序释放内存资源,避免内存泄漏问题。当内存不足时,GC 会回收软引用和弱引用所指向的对象,以释放内存资源。使用内存缓存技术:在加载图片等资源时,可以使用内存缓存技术来减少网络请求,提高应用程序的性能。使用 ProGuard 优化:ProGuard 是一个 Java 代码混淆工具,可以帮助应用程序减少 APK 大小,提高应用程序的性能。及时关闭无用的服务和线程:当应用程序不再使用服务和线程时,应及时关闭这些服务和线程,以释放内存资源。使用 LeakCanary 检测内存泄漏问题:LeakCanary 是一个内存泄漏检测库,可以帮助开发者快速定位内存泄漏问题,以减少内存泄漏问题对应用程序性能的影响。
在 Android 应用开发中,布局优化也是一项非常重要的工作,它直接关系到应用的运行效率和用户体验。以下是一些常见的布局优化细节:
减少嵌套层数:减少布局嵌套层数可以减小布局层级,提高布局性能。使用 ConstraintLayout:ConstraintLayout 支持多个 View 之间相对位置的约束,使用 ConstraintLayout 可以减少布局嵌套,提高布局性能。使用 RecyclerView:RecyclerView 是 Android 官方提供的用于展示大量数据列表的组件,它支持视图复用、惰性加载等功能,可以有效提高布局性能。避免过度绘制:在布局中,避免使用不必要的背景或者绘制过于复杂的 View,可以减少布局的过度绘制。避免布局中出现过多的 View:布局中过多的 View 会增加布局的复杂度,降低布局性能,可以使用合适的布局方式减少 View 的数量。使用缓存技术:可以使用缓存技术来优化布局性能,例如在 ListView 中使用 ViewHolder 缓存 ItemView,可以减少 View 的创建和销毁。使用 ViewStub:ViewStub 是一个轻量级的 View,可以在需要时动态加载布局,减少布局文件中的无用 View。使用 include 标签:在布局中,使用 include 标签可以复用布局文件,减少布局文件的重复。使用 merge 标签:在布局中,使用 merge 标签可以减少布局嵌套层数,提高布局性能。使用权重值:在 LinearLayout 中,使用权重值可以实现按比例分配布局空间,避免过度布局。
标签: #android内存管理机制面试