Android性能优化篇
1. 什么是内存泄漏?
内存泄漏指的是程序运行时未能正确释放不再使用的内存资源,导致这些内存资源无法被垃圾回收器回收和重新利用。内存泄漏会导致程序占用越来越多的内存,最终可能导致内存耗尽和程序崩溃。
在Java中,当一个对象不再被引用时,Java的垃圾回收器会自动将其标记为可回收,并在合适的时机释放其占用的内存。然而,如果存在内存泄漏的情况,这些不再使用的对象仍然被保留在内存中,无法被垃圾回收器回收。内存泄漏可能是由于编程错误、资源管理不当或设计问题引起的。
2. 什么是内存溢出?
内存溢出(Out of Memory Error,OOM)是指程序在申请内存时,没有足够的内存可供使用,从而抛出异常或错误。
当程序试图申请的内存超过Java虚拟机(JVM)所允许的最大内存时,就会发生内存溢出。这通常是由于程序中存在内存泄漏、大量对象未被及时回收或堆内存分配不当等问题导致的。
内存溢出会导致程序崩溃或抛出异常,如java.lang.OutOfMemoryError。为了解决内存溢出问题,需要仔细检查程序的内存使用情况,找出内存泄漏的原因并修复它。
3. 在Android中,有哪些场景会导致内存泄漏,要怎么解决?
- 非静态内部类的静态示例
private static Object innerClass;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
view = findViewById(R.id.view);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
createInnerClass();
finish();
}
});
}
void createInnerClass() {
class InnerClass {}
innerClass = new InnerClass();
}
执行createInnerClass时非静态内部类InnerClass实例innerClass的生命周期会和程序一样长,一直持有Activity的引用,导致Activity没法被回收产生内存泄漏。
- 多线程相关的匿名内部类/非静态内部类
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
view = findViewById(R.id.view);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startAsyncTask();
finish();
}
});
}
void startAsyncTask() {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... voids) {
while (true);
}
}.execute();
}
解决办法:
自定义一个静态的AsyncTask,如:
private static class MyAsyncTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... voids) {
while (true);
}
}
void startAsyncTask() {
new MyAsyncTask().execute();
}
- Handler导致的内存泄漏
解决办法:1.自定义的静态handler 2.可以加一个弱引用 3.还有一个主意的就是当你activity被销毁的时候如果还有消息没有发出去 就remove掉吧 4.removecallbacksandmessages去清除Message和Runnable 加null 写在生命周的ondestroy()就行
- Context使用不当
- 静态view 6.WebView的使用
在Android开发中,如果我们在xml文件中定义WebView,那么WebView就会对当前的Activity持有引用。这样,当Activity无法正常销毁时,就会导致Activity的内存泄露。
解决办法:
(1)直接 new WebView 并传入 application context 代替在 XML 里面声明以防止 activity 引 用被滥用导致内存泄漏。
创建:
vWeb = new WebView(getContext().getApplicationContext());
container.addView(vWeb);
销毁:
@Override
protected void onDestroy() {
super.onDestroy();
if (vWeb != null) {
vWeb.setWebViewClient(null);
vWeb.setWebChromeClient(null);
vWeb.loadDataWithBaseURL(null, "", "text/html", "utf-8", null);
vWeb.clearHistory();
((ViewGroup) vWeb.getParent()).removeView(vWeb);
vWeb.destroy();
vWeb = null;
}
}
(2)WebView单开一个进程,使用AIDL与应用的主进程进行通信,根据业务需求在合适的时机销毁WebView进程。
- 资源对象未关闭,如Cursor,File等
- Bitmap对象未回收
- 监听器未关闭,如register和unregister,广播,EventBus等。
4. 哪些情况下会导致OOM问题?如何解决?
- 过多的内存泄漏会导致内存溢出 2. 加载大的图片 3. 创建过多的线程
内存优化的解决方法: 1.申请更大的内存,比如多进程、设置manifest中的largeHeap=true等。 2.减少内存使用 ①使用优化后的集合对象,分场景使用SpaseArray和HashMap; ②使用微信的mmkv替代sharedpreference; ③使用StringBuilder替代String拼接 ④统一带有缓存的基础库,特别是图片库,如果用了两套不一样的图片加载库就会出现2个图片各自维护一套图片缓存 ⑤给ImageView设置合适尺寸的图片,列表页显示缩略图,查看大图显示原图 ⑥优化业务架构设计,比如省市区数据分批加载,需要加载省就加载省,需要加载市就加载失去,避免一下子加载所有数据 3.避免内存泄漏
5. ANR 出现的场景以及解决方案?
场景: 1、触摸无响应5s 2、BroadCastReciver 前台处理超过10s 后台超过60s 3、Server 前台处理超过20s 后台超过200s
ANR出现的类型有两种 1、主线程耗时导致 2、CPU、内存、IO 占用过高资源耗尽(其他进程也可以导致)
如何避免: 1、不要在主线程中做耗时的操作 2、避免CPU占用过高,简化方法,减少执行时间 3、避免内存占用过高,防止内存泄漏
6. 性能优化的方式有哪些?
- 布局优化:通过减少布局文件的层级,使用ConstraintLayout等轻量级布局,减少布局层次,优化布局结构,可以提高应用程序的性能(合理使用include,merge,viewStub等使用)。
- 绘制优化:使用高压缩比的图片,避免产生过多的内存开销。另外,可以通过Canvas、OpenGL等技术进行自定义绘制,提高绘制性能。
- 内存泄漏优化:检查代码中是否存在内存泄漏,例如静态变量持有大对象、注册的对象未注销、资源性对象未关闭、Handler临时性内存泄漏以及容器中的对象没清理造成内存泄漏等问题,并采取相应的措施进行修复。
- 线程优化:在Android中,UI线程是主线程,所有与UI相关的操作都应该在主线程中执行。如果某些操作需要耗时较长,可以使用异步线程进行执行,避免阻塞主线程,从而提高用户体验。
- 使用缓存:合理使用缓存可以减少数据库访问次数和网络请求次数,从而提高应用程序的性能。
- 网络请求优化:减少HTTP请求:通过合并图片、减少图片大小、使用缓存等方式可以减少HTTP请求次数,从而提高应用程序的性能,使用 Gzip 压缩 Response 减少数据传输量;使用 Protocol Buffer 代替 JSON。
- 数据库查询优化:通过索引、分页查询、批量操作等方式可以优化数据库查询性能。
- 电量优化:避免轮循。可以利用推送。如果非要轮循,合理的设置频率。应用处于后台时,避免某些数据的传输,比如感应器,定位,视频缓存。页面销毁时,取消掉网络请求。限制访问频率,失败后不要无限的重连等。
7. 什么是内存抖动,哪些场景会出现内存抖动?
在Android开发中,内存抖动(Memory Churning)是指程序不断地分配和回收内存,导致内存的频繁波动,进而引发系统频繁的垃圾回收,从而导致系统性能下降的现象。
内存抖动通常发生在以下场景:
- 大量创建和销毁临时对象:如果程序中存在大量创建和销毁临时对象的操作,就会导致内存抖动。例如,频繁地创建和销毁大量的字符串、数组、集合等对象。
- 频繁的内存分配和回收:如果程序中存在频繁的内存分配和回收操作,就会导致内存抖动。例如,大量地使用HashMap、ArrayList等数据结构,并在每次操作后立即回收它们的内存。
- 大对象的使用:如果程序中存在大对象的使用,也会导致内存抖动。例如,频繁地读取和写入大量的数据到文件、数据库等,或者一次性加载大量的图片、视频等资源。
为了避免内存抖动,可以采取以下措施:
- 减少临时对象的创建和销毁:尽量避免频繁地创建和销毁临时对象,可以使用对象池、缓存等技术来重用对象。
- 合理使用数据结构:避免频繁地创建和回收数据结构,可以使用可重用的数据结构或者自定义的数据结构来减少内存分配和回收的次数。
- 减少大对象的使用:尽量避免一次性加载大量的数据或者资源,可以使用分页加载、懒加载等技术来减少内存占用。
- 如避免在循环遍历时创建临时大对象,不在自定义View时在onDraw里创建对象等。
7. apk如何瘦身?
- 图片压缩:使用工具对图片进行压缩,减少图片的大小(如合理使用shape替代图片,webp,svg替代png,jpg格式等),从而减小APK的大小。
- 代码混淆:使用代码混淆工具对代码进行混淆,减少代码的可读性和可维护性,同时减小APK的大小。
- 移除不需要的资源:检查项目中是否包含不需要的资源文件,如冗余的图片、音频、视频等,将其移除可以减小APK的大小。
- 使用Proguard:Proguard是一个代码优化工具,可以对代码进行优化和混淆,减小APK的大小。
- 启用APK拆分:Android支持APK拆分,可以将APK拆分为多个模块,从而减小APK的大小。
- 压缩资源文件:使用工具对资源文件进行压缩,如对字符串资源进行压缩,从而减小APK的大小。
- 移除未使用的库:检查项目中是否包含未使用的库,将其移除可以减小APK的大小。
8. 请谈谈你是如何进行多渠道打包的?
- productFlavor
- 如果不涉及apk类和资源改动,仅仅是某些配置信息,用walle(美团)更快
- 第三方的类似腾讯(VasDolly)
9. android中的热更新方案有哪些?
- DexClassLoader:DexClassLoader是Android系统提供的一个类加载器,它可以在运行时动态加载DEX文件。通过将新的DEX文件上传到服务器,并在客户端下载并加载新的DEX文件,可以实现热更新。但需要注意的是,多个DEX文件的加载顺序和冲突问题需要妥善处理。
- Multidex:Multidex是Android平台提供的一种支持多个DEX文件的方式。通过使用Multidex,可以将应用程序的代码分割成多个DEX文件,并在运行时动态加载和卸载这些文件。这种方式可以更好地管理代码的动态更新和扩展性。
- Tinker:Tinker是腾讯开发的一款Android热更新框架,它基于DexClassLoader实现动态加载。Tinker提供了更加完善的热更新机制,包括增量更新、依赖分析、版本兼容性校验等功能,可以更加高效地进行应用代码的动态更新。
- AndFix:AndFix是阿里巴巴开源的一款Android热修复框架,它基于Native层的hook技术实现动态修复。AndFix可以在运行时替换指定方法的实现,从而实现对应用代码的动态更新。
- Robust:Robust是美团的一款Instant-Run插桩方案:在出包apk包编译阶段对Java层每个方法的前面都织入一段控制执行逻辑代码。 优缺点:
10. 设计模式和网络相关