Android面试题内存&性能篇

2023-11-20

Android面试题内存&性能篇,由本人整理汇总,后续将继续推出系列篇,如果喜欢请持续关注和推荐,更多内容可以关注微信公众号(Android高级编程):android-tech

系列文章目录:

内存分配

RAM(random access memory)随机存取存储器。说白了就是内存。 一般Java在内存分配时会涉及到以下区域:

  • 寄存器(Registers):速度最快的存储场所,因为寄存器位于处理器内部,我们在程序中无法控制
  • 栈(Stack):存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中
  • 堆(Heap):堆内存用来存放由new创建的对象和数组。在堆中分配的内存,由Java虚拟机的自动垃圾回收器(GC)来管理。
  • 静态域(static field): 静态存储区域就是指在固定的位置存放应用程序运行时一直存在的数据,Java在内存中专门划分了一个静态存储区域来管理一些特殊的数据变量如静态的数据变量
  • 常量池(constant pool):虚拟机必须为每个被装载的类型维护一个常量池。常量池就是该类型所用到常量的一个有序集和,包括直接常量(string,integer和floating point常量)和对其他类型,字段和方法的符号引用。
  • 非RAM存储:硬盘等永久存储空间

堆栈存储特点对比:

  • 栈:当定义一个变量时,Java就在栈中为这个变量分配内存空间,当该变量退出该作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。
  • 堆:当堆中的new产生数组和对象超出其作用域后,它们不会被释放,只有在没有引用变量指向它们的时候才变成垃圾,不能再被使用。即使这样,所占内存也不会立即释放,而是等待被垃圾回收器收走。这也是Java比较占内存的原因。

堆栈运行特点对比:

  • 栈:存取速度比堆要快,仅次于寄存器。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。
  • 堆:堆是一个运行时数据区,可以动态地分配内存大小,因此存取速度较慢。也正因为这个特点,堆的生存期不必事先告诉编译器,而且Java的垃圾收集器会自动收走这些不再使用的数据。

对象引用类型:

引用分为四种级别,这四种级别由高到低依次为:强引用>软引用>弱引用>虚引用。

  • 强引用(strong reference)
    如:Object object=new Object(),object就是一个强引用了。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。
  • 软引用(SoftReference)
    只有内存不够时才回收,常用于缓存;当内存达到一个阀值,GC就会去回收它;
  • 弱引用(WeakReference)
    弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它 所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。
  • 虚引用(PhantomReference)
    "虚引用"顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。

UI优化

  • a.合理选择RelativeLayout、LinearLayout、FrameLayout,RelativeLayout会让子View调用2次onMeasure,而且布局相对复杂时,onMeasure相对比较复杂,效率比较低,LinearLayout在weight>0时也会让子View调用2次onMeasure。LinearLayout weight测量分配原则。
  • b.使用标签<include><merge><ViewStub>
  • c.减少布局层级,可以通过手机开发者选项>GPU过渡绘制查看,一般层级控制在4层以内,超过5层时需要考虑是否重新排版布局。
  • d.自定义View时,重写onDraw()方法,不要在该方法中新建对象,否则容易触发GC,导致性能下降
  • e.使用ListView时需要复用contentView,并使用Holder减少findViewById加载View。
  • f.去除不必要背景,getWindow().setBackgroundDrawable(null)
  • g.使用TextView的leftDrawabel/rightDrawable代替ImageView+TextView布局

内存优化

主要为了避免OOM和频繁触发到GC导致性能下降

  • a.Bitmap.recycle(),Cursor.close,inputStream.close()
  • b.大量加载Bitmap时,根据View大小加载Bitmap,合理选择inSampleSize,RGB_565编码方式;使用LruCache缓存
  • c.使用 静态内部类+WeakReference 代替内部类,如Handler、线程、AsyncTask
  • d.使用线程池管理线程,避免线程的新建
  • e.使用单例持有Context,需要记得释放,或者使用全局上下文
  • f.静态集合对象注意释放
  • g.属性动画造成内存泄露
  • h.使用webView,在Activity.onDestory需要移除和销毁,webView.removeAllViews()和webView.destory()

备:使用LeakCanary检测内存泄露

响应速度优化

Activity如果5秒之内无法响应屏幕触碰事件和键盘输入事件,就会出现ANR,而BroadcastReceiver如果10秒之内还未执行操作也会出现ANR,Serve20秒会出现ANR 为了避免ANR,可以开启子线程执行耗时操作,但是子线程不能更新UI,因此需要Handler消息机制、AsyncTask、IntentService进行线程通信。

备:出现ANR时,adb pull data/anr/tarces.txt 结合log分析

其他性能优化

  • a.常量使用static final修饰
  • b.使用SparseArray代替HashMap
  • c.使用线程池管理线程
  • d.ArrayList遍历使用常规for循环,LinkedList使用foreach
  • e.不要过度使用枚举,枚举占用内存空间比整型大
  • f.字符串的拼接优先考虑StringBuilder和StringBuffer
  • g.数据库存储是采用批量插入+事务

Android内存泄露及管理

(1)内存溢出(OOM)和内存泄露(对象无法被回收)的区别。 (2)引起内存泄露的原因
(3)内存泄露检测工具---->LeakCanary

内存溢出 out of memory:是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出。内存溢出通俗的讲就是内存不够用。

内存泄露 memory leak:是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光

内存泄露原因:

  1. Handler 引起的内存泄漏。
    解决:将Handler声明为静态内部类,就不会持有外部类SecondActivity的引用,其生命周期就和外部类无关,如果Handler里面需要context的话,可以通过弱引用方式引用外部类
  2. 单例模式引起的内存泄漏。
    解决:Context是ApplicationContext,由于ApplicationContext的生命周期是和app一致的,不会导致内存泄漏
  3. 非静态内部类创建静态实例引起的内存泄漏。
    解决:把内部类修改为静态的就可以避免内存泄漏了
  4. 非静态匿名内部类引起的内存泄漏。
    解决:将匿名内部类设置为静态的。
  5. 注册/反注册未成对使用引起的内存泄漏。
    注册广播接受器、EventBus等,记得解绑。
  6. 资源对象没有关闭引起的内存泄漏。
    在这些资源不使用的时候,记得调用相应的类似close()、destroy()、recycler()、release()等方法释放。
  7. 集合对象没有及时清理引起的内存泄漏。
    通常会把一些对象装入到集合中,当不使用的时候一定要记得及时清理集合,让相关对象不再被引用。

JAVA相关性能优化

1 不用new关键词创建类的实例
用new关键词创建类的实例时,构造函数链中的所有构造函数都会被自动调用。但如果一个对象实现了Cloneable接口,我们可以调用它的clone()方法。clone()方法不会调用任何类构造函数。

在使用设计模式(Design Pattern)的场合,如果用Factory模式创建对象,则改用clone()方法创建新的对象实例非常简单。例如,下面是Factory模式的一个典型实现:
public static Credit getNewCredit() {
    return new Credit();
}
改进后的代码使用clone()方法,如下所示:
private static Credit BaseCredit = new Credit();
public static Credit getNewCredit() {
    return (Credit) BaseCredit.clone();
}

上面的思路对于数组处理同样很有用。

2 使用非阻塞I/O
版本较低的JDK不支持非阻塞I/O API。为避免I/O阻塞,一些应用采用了创建大量线程的办法(在较好的情况下,会使用一个缓冲池)。这种技术可以在许多必须支持并发I/O流的应用中见 到,如Web服务器、报价和拍卖应用等。然而,创建Java线程需要相当可观的开销。 JDK 1.4引入了非阻塞的I/O库(java.nio)。如果应用要求使用版本较早的JDK,在这里有一个支持非阻塞I/O的软件包。

3 慎用异常
异 常对性能不利。抛出异常首先要创建一个新的对象。Throwable接口的构造函数调用名为fillInStackTrace()的本地(Native) 方法,fillInStackTrace()方法检查堆栈,收集调用跟踪信息。只要有异常被抛出,VM就必须调整调用堆栈,因为在处理过程中创建了一个新 的对象。 异常只能用于错误处理,不应该用来控制程序流程。

4 不要重复初始化变量
默认情况下,调用类的构造函数时, Java会把变量初始化成确定的值:所有的对象被设置成null,整数变量(byte、short、int、long)设置成0,float和 double变可柚贸?.0,逻辑值设置成false。当一个类从另一个类派生时,这一点尤其应该注意,因为用new关键词创建一个对象时,构造函数链中 的所有构造函数都会被自动调用。

5 尽量指定类的final修饰符
带有final修饰符的类是不可派生的。在Java核心API中,有许多应用final的例子,例如java.lang.String。为String类指定final防止了人们覆盖length()方法。 另外,如果指定一个类为final,则该类所有的方法都是final。Java编译器会寻找机会内联(inline)所有的final方法(这和具体的编译器实现有关)。此举能够使性能平均提高50%。

6 尽量使用局部变量
调用方法时传递的参数以及在调用中创建的临时变量都保存在栈(Stack)中,速度较快。其他变量,如静态变量、实例变量等,都在堆(Heap)中创建,速度较慢。另外,依赖于具体的编译器/JVM,局部变量还可能得到进一步优化。请参见《尽可能使用堆栈变量》。

7 乘法和除法
考虑下面的代码: for (val = 0; val < 100000; val +=5) { alterX = val * 8; myResult = val * 2; } 用移位操作替代乘法操作可以极大地提高性能。下面是修改后的代码: for (val = 0; val < 100000; val += 5) { alterX = val << 3; myResult = val << 1; }

8.字符串拼接
不要随意的使用stingA=StringB+StringC的写法,有大量拼接操作的地方用StringBuilder代替

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android面试题内存&性能篇 的相关文章

  • 来自十六进制代码的 Apache POI XSSFColor

    我想将单元格的前景色设置为十六进制代码中的给定颜色 例如 当我尝试将其设置为红色时 style setFillForegroundColor new XSSFColor Color decode FF0000 getIndexed 无论我在
  • 通过列表视图检查动态生成的复选框时遇到问题

    我知道其他成员已经提出了这个问题 一些成员也给出了解决方案 但问题是我没有找到任何适合我的应用程序的解决方案 我正在创建一个应用程序 其中我有一个屏幕 它将显示动态列表视图 其中包含列表项 复选框和三个文本视图 一个用于候选人姓名 另外两个
  • jar 中的 apklib 有什么优点?

    我正在关注这个问题 https stackoverflow com questions 6059502 whats the difference between apklib and jar files但它并没有完全回答我的问题 jar 中
  • 从手机访问本地主机[关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 我正在使用
  • 使用 Guice 优化注册表

    你好 今天思考了一种优化 有一些疑问 语境 我正在使用 Guice 2 进行 Java 开发 在我的网络应用程序中 我有一个转换器注册表 可以即时转换为某种类型 转换器描述如下 public class StringToBoolean im
  • Java Swing For mac 中的 DJ Native Swing 浏览器

    我有一个用 Swing 制作的 Java 应用程序 并且使用了一个 DJ Native Swing 浏览器 当我尝试在 OS X 上使用它时 它抛出了一个NoClassDefFoundError尽管我添加了 swt jar 但始终如此 有人
  • 如何避免 ArrayIndexOutOfBoundsException 或 IndexOutOfBoundsException? [复制]

    这个问题在这里已经有答案了 如果你的问题是我得到了java lang ArrayIndexOutOfBoundsException在我的代码中 我不明白为什么会发生这种情况 这意味着什么以及如何避免它 这应该是最全面的典范 https me
  • 流中的非终结符 forEach() ?

    有时 在处理 Java Stream 时 我发现自己需要一个非终端 forEach 来触发副作用但不终止处理 我怀疑我可以用 map item gt f item 之类的方法来做到这一点 其中方法 f 执行副作用并将项目返回到流中 但这似乎
  • Android:确定 2.2 及更高版本上的摄像头数量

    我的应用程序需要在 Android 2 2 及更高版本上运行 我需要一种方法来确定可用摄像机的数量 有很多帖子解决了这个问题 但我找不到一个有效的 一种解决方案是简单地检测操作系统版本 任何 2 2 版本的设备都仅限于 1 个摄像头 即使该
  • Docker 和 Eureka 与 Spring Boot 无法注册客户端

    我有一个使用 Spring Boot Docker Compose Eureka 的非常简单的演示 我的服务器在端口 8671 上运行 具有以下应用程序属性 server port 8761 eureka instance prefer i
  • java库维护数据库结构

    我的应用程序一直在开发 所以偶尔 当版本升级时 需要创建 更改 删除一些表 修改一些数据等 通常需要执行一些sql代码 是否有一个 Java 库可用于使我的数据库结构保持最新 通过分析类似 db structure version 信息并执
  • “无法实例化活动”错误

    我的一个 Android 应用程序拥有大约 100 000 个用户 每周大约 10 次 我会通过 Google 的市场工具向我报告以下异常情况 java lang RuntimeException Unable to instantiate
  • Resteasy 可以查看 JAX-RS 方法的参数类型吗?

    我们使用 Resteasy 3 0 9 作为 JAX RS Web 服务 最近切换到 3 0 19 我们开始看到很多RESTEASY002142 Multiple resource methods match request警告 例如 我们
  • 如何在Android中解析xml类型的HTTPResponse

    我有一个 Android 应用程序 我使用 POST 方法来获取响应 这是我的代码 HttpResponse httpResponse httpclient execute httppost HttpEntity resEntity htt
  • 如何重新启动死线程? [复制]

    这个问题在这里已经有答案了 有哪些不同的可能性可以带来死线程回到可运行状态 如果您查看线程生命周期图像 就会发现一旦线程终止 您就无法返回到新位置 So 没有办法将死线程恢复到可运行状态 相反 您应该创建一个新的 Thread 实例
  • Java中HashMap和ArrayList的区别?

    在爪哇 ArrayList and HashMap被用作集合 但我不明白我们应该在哪些情况下使用ArrayList以及使用时间HashMap 他们两者之间的主要区别是什么 您具体询问的是 ArrayList 和 HashMap 但我认为要完
  • 如何使用play框架上传多个文件?

    我在用play framework 2 1 2 使用java我正在创建视图来上传多个文件 我的代码在这里 form action routes upload up enctype gt multipart form data
  • Android ADT Eclipse 插件,parseSDKContent 失败

    我刚刚设置了我的第一个 Android 开发环境 其中包括 日食3 5 Mac OS X 10 5 适用于 x86 mac 的 Android SDK ADT Eclipse 插件 0 9 6 我已将 set PATH 设置为我的 SDK
  • 在浏览器刷新中刷新检票面板

    我正在开发一个付费角色系统 一旦用户刷新浏览器 我就需要刷新该页面中可用的统计信息 统计信息应该从数据库中获取并显示 但现在它不能正常工作 因为在页面刷新中 java代码不会被调用 而是使用以前的数据加载缓存的页面 我尝试添加以下代码来修复
  • Java EE 目录结构

    我对以下教程有疑问 http www mkyong com jsf2 jsf 2 internationalization example http www mkyong com jsf2 jsf 2 internationalizatio

随机推荐

  • 计算机丢失MSVCR120.dll是什么意思,电脑找不到MSVCR120.dll如何修复?

    我们在玩游戏或者运行一些软件的时候 系统提示无法启动此程序 因为计算机中丢失MSVCR120 dll 尝试重新安装该程序以解决此问题 这个需要怎么修复呢 详细困扰着不少小伙伴 小编今天就把教程分享给大家 方法如下 首先是打开电脑浏览器后在顶
  • Java判断时间是否超过30天,java 字符串时间 判断是否在30天内

    时间是字符串类型时 比较大小的时候 先要 转化成 时间格式 然后在进行比较 字符串比较大小的规则 首先取出两个字符串的长度 比较较小的长度内 两者是否相等 若不相等 则直接返回该位置字符的ASCII码相减后的值 若各位置都相等 则将两个字符
  • 问题 A: 天天向上

    题目描述 假设某同学初始能力值为1 现在该同学学习10天 休息1天 学习一天 能力提升0 001 休息一天 能力下降0 001 问一年 365天 后该同学的能力是多少 输出 365天后该同学的能力是 保留小数点6位 分析 书上76页有类似的
  • STM32 串行FLASH文件系统FatFs

    目录 一 Windows系统为例 二 文件系统的结构与特性 为什么要应用文件分配表 三 FatFs文件系统 1 FatFs 文件系统源码介绍 2 FatFs在程序中的关系网 四 配置FatFs移植程序 1 配置diskio c文件 2 配置
  • MobaXterm x11-forwarding

    Linux系统也是有图像界面的 它的方式和Windows不一样 叫做 X Window 采用的是X11协议 X11 中的 X 指的就是 X 协议 11 指的是采用 X 协议的第 11 个版本 客户端是X server 用MobaXterm登
  • CocosCretor解决premultipliedAlpha黑边问题

    在官方文档中的说明 premultipliedAlpha 对于是否启动贴图预乘 当图片的透明区域出现色块时 需要关闭该选项 当图片的半透明区域颜色变黑时 需要启用该选项 之前在项目中导出的spine有黑边问题 也就是半透明区域颜色变黑 然后
  • 《软件测试的艺术》第五章 模块(单元)测试

    软件测试的艺术 第五章 模块 单元 测试 5 0 前言 5 1 测试用例设计 5 2 增量测试 5 3 自顶向下测试和自底向上测试 5 3 1 自顶向下的测试 5 3 2 自底向上的测试 5 3 3 比较 5 4 执行测试 5 5 小结 参
  • vite-svg-loader,在项目里轻松使用svg,ts项目需特别注意!

    前言 vite svg loader插件可以让我们像使用vue组件那样使用svg图 使用起来超级方便 安装 npm install vite svg loader save dev 使用 1 vite config ts配置 import
  • 解决Flutter键盘弹起导致与输入框有间距问题(Flutter键盘弹起Scaffold布局流程)解析

    一 在项目中遇到了个如下问题 当页面底部有个输入框 点击弹出键盘时 输入框与键盘之间有一段间距 通过排除 最后找到了问题根源所在 原因是使用了这个屏幕适配框架导致的 此框架通过直接修改FlutterViewConfiguration 的si
  • Spring boot中,feign远程调用api,用@SpringQueryMap接收GET请求参数,自定义QueryMapEncoder处理特殊类型的参数转换

    feign远程调用时 get请求时 如果有特殊的字段类型 用 SpringQueryMap接收参数时 会出现异常 需要自定义QueryMapEncoder 本文例举OffsetDateTime字段类型处理 1 OffsetDateTimeQ
  • 性能测试 —— Tomcat监控与调优:status页监控

    Tomcat服务器是一个免费的开放源代码的Web 应用服务器 Tomcat是Apache 软件基金会 Apache Software Foundation Jakarta 项目中的一个核心项目 由Apache Sun 和其他一些公司及个人共
  • 圆石说│彭一鸣:运用区块链技术赋能实体旅游产业;微软开放6万项专利包括一个开源区块链项目……

    智联招聘 区块链岗位需求主要集中在一线和新一线城市 智联招聘报告显示 从目前区块链职位的城市分布来看 该领域的岗位需求主要集中在一线和新一线城市中 其中 北京 上海和深圳位于第一梯队 职位占比分别达到24 20 和10 杭州 广州和成都紧随
  • spacemacs复制minibuffer的内容到buffer里

    spacemacs复制minibuffer的内容到buffer里 获取当前buffer的绝对路径 spacemacs复制minibuffer的内容到buffer里 不常用 但可以开阔一下视野 即 发现helm里 还有可进一步操作的命令 举例
  • pil_openvcv_scikit-image_tensorflow四种读图方式对比

    文章目录 1 四种不同的库读取jpg图显示 2 评估所读图片的差异 3 简单说明有差异原因 4 同样的流程对png图片进行处理 5 png图片转jpg 5 1 使用PIL进行转换 5 2 使用Opencv进行转换 5 3 使用Tensorf
  • asp.net ajax跨域访问,支持Ajax跨域访问ASP.NET Web Api 2(Cors)的示例教程

    随着深入使用ASP NET Web Api 我们可能会在项目中考虑将前端的业务分得更细 比如前端项目使用Angularjs的框架来做UI 而数据则由另一个Web Api 的网站项目来支撑 注意 这里是两个Web网站项目了 前端项目主要负责界
  • 【图像处理】非线性滤波

    非线性滤波 图像处理中滤波分线性滤波和非线性滤波两种 其中常见的线性滤波有 方框滤波 中值滤波 高斯滤波等 其主要原理就是每个像素的输出值是输入像素的加权和 所以像素的输入与输出成线性关系 线性滤波器易于构造 并且易于从频域响应角度进行分析
  • 【电路设计】220V AC转低压DC电路概述

    前言 最近因项目需要 电路板上要加上一个交流220V转低压直流 比如12V或者5V这种 一般来说 比较常见也比较简单的做法是使用一个变压器将220V AC进行降压 比如降到22V AC 但是很遗憾的是 支持220V的变压器一般体积很大 而板
  • Pycharm常用快捷键

    成长就是将你的一切都变成心静如水 将一切情绪都调整到静音模式 一 Pycharm常用快捷键 查找 CTRL F 全局查找 CTRL shift F 撤销 CTRL Z 缩进 Tab 行首 HOME 快速修正 alt enter 复写代码 C
  • chatgpt赋能python:如何使用Python进行SEO优化

    如何使用Python进行SEO优化 在数字化时代 SEO已经成为一个广泛使用且需求不断增加的领域 虽然有很多工具和技术可以用于SEO 但Python是其中之一 Python是一种现代编程语言 通常用于处理大数据集 自动化任务 Web开发等特
  • Android面试题内存&性能篇

    Android面试题内存 性能篇 由本人整理汇总 后续将继续推出系列篇 如果喜欢请持续关注和推荐 更多内容可以关注微信公众号 Android高级编程 android tech 系列文章目录 Android面试题View篇 Android面试