热文导读| 点击标题阅读
41岁程序员被裁,北京有1500万房产,程序员:我该不该退休?
裸辞两个月,海投一个月,从 Android 转战 Web 前端的求职之路
原文来源:https://www.jianshu.com/p/11eb07273478
书籍推荐
市面上android性能优化的书籍不多,因为性能优化这块稍微深入一点,涉及知识的深度和广度就比较大了,而且性能优化依赖很多的平台相关的工具和分析技巧,导致通用性和实效性又不太高,所以以下书籍的内容也比较浅尝辄止
移动App性能评测与优化
Android移动性能实战
Android应用性能优化
内存性能分析及优化的意义
Overview of memory management
内存管理介绍
OOM
Low Memory Killer
GC
综上
关注并减少应用的内存消耗可以减少oom的概率,在内存紧张的场景下获得更好的用户体验,也可以增加应用的后台存活时间
工具介绍
调查 RAM 使用情况
dumpsys procstats
用来衡量一段时间内应用消耗内存的情况
(最小PSS-平均PSS-最大PSS/最小USS-平均USS-最大USS)
![procstats 640?wx_fmt=jpeg](https://i-blog.csdnimg.cn/blog_migrate/868cf5b0107ed7b657af783c5ab22263.jpeg)
LeakCanary
检测内存泄漏的工具
MAT
比较常用的内存dump文件分析工具
使用方法
hprof-conv -z src dst //-z可以排除android框架创建的对象
使用场景
分析场景构建
性能测试的一些注意点
常见的性能测试方式
容易出现内存问题的场景
常见的内存问题
内存泄漏
内存泄漏产生的原因
一个对象的生命周期已经结束了,但是有其他对象持有了它的实例导致无法在GC时被回收,在Android中通常是Activity在finish之后依然有对象引用它导致内存泄漏
内存泄漏的常见场景
内存泄漏在分析工具上的表现
![内存泄漏 640?wx_fmt=jpeg](https://i-blog.csdnimg.cn/blog_migrate/c41d953b4d7856ccb23b163df7b02ccb.jpeg)
每次activity的重建都会造成内存上升且gc不会使内存使用降低
内存泄漏的避免
内存抖动
内存抖动的原因
内存抖动一般是瞬间创建了大量对象,会在短时间内触发多次GC,产生卡顿
内存抖动的场景
内存抖动的在分析工具上的表现
![内存抖动 640?wx_fmt=jpeg](https://i-blog.csdnimg.cn/blog_migrate/0475a008f7ea1b3f4974b7a381a291c6.jpeg)
制造了一个内存抖动的场景
public void testThrashing(boolean needLog) { int dimension = 300; int[][] lotsOfInts = new int[dimension][dimension]; Random randomGenerator = new Random(); for (int i = 0; i < lotsOfInts.length; i++) { for (int j = 0; j < lotsOfInts[i].length; j++) { lotsOfInts[i][j] = randomGenerator.nextInt(); } } //优化以前 for (int i = 0; i < lotsOfInts.length; i++) { String rowAsStr = ""; int[] sorted = getSorted(lotsOfInts[i]); for (int j = 0; j < lotsOfInts[i].length; j++) { rowAsStr += sorted[j]; if (j < (lotsOfInts[i].length - 1)) { rowAsStr += ", "; } } if (needLog) { Log.i(TAG, "Row " + i + ": " + rowAsStr); } } } public void optimizeThrashing() { int dimension = 300; int[][] lotsOfInts = new int[dimension][dimension]; Random randomGenerator = new Random(); for (int i = 0; i < lotsOfInts.length; i++) { for (int j = 0; j < lotsOfInts[i].length; j++) { lotsOfInts[i][j] = randomGenerator.nextInt(); } } //优化以后 StringBuilder sb = new StringBuilder(); for (int i = 0; i < lotsOfInts.length; i++) { sb.delete(0, sb.length()); int[] sorted = getSorted(lotsOfInts[i]); for (int j = 0; j < lotsOfInts[i].length; j++) { sb.append(sorted[j]); if (j < (lotsOfInts[i].length - 1)) { sb.append(", "); } } Log.e(TAG, "Row " + i + ": " + sb); } }
int dimension = 300;
int[][] lotsOfInts = new int[dimension][dimension];
Random randomGenerator = new Random();
for (int i = 0; i < lotsOfInts.length; i++) {
for (int j = 0; j < lotsOfInts[i].length; j++) {
lotsOfInts[i][j] = randomGenerator.nextInt();
}
}
//优化以前
for (int i = 0; i < lotsOfInts.length; i++) {
String rowAsStr = "";
int[] sorted = getSorted(lotsOfInts[i]);
for (int j = 0; j < lotsOfInts[i].length; j++) {
rowAsStr += sorted[j];
if (j < (lotsOfInts[i].length - 1)) {
rowAsStr += ", ";
}
}
if (needLog) {
Log.i(TAG, "Row " + i + ": " + rowAsStr);
}
}
}
public void optimizeThrashing() {
int dimension = 300;
int[][] lotsOfInts = new int[dimension][dimension];
Random randomGenerator = new Random();
for (int i = 0; i < lotsOfInts.length; i++) {
for (int j = 0; j < lotsOfInts[i].length; j++) {
lotsOfInts[i][j] = randomGenerator.nextInt();
}
}
//优化以后
StringBuilder sb = new StringBuilder();
for (int i = 0; i < lotsOfInts.length; i++) {
sb.delete(0, sb.length());
int[] sorted = getSorted(lotsOfInts[i]);
for (int j = 0; j < lotsOfInts[i].length; j++) {
sb.append(sorted[j]);
if (j < (lotsOfInts[i].length - 1)) {
sb.append(", ");
}
}
Log.e(TAG, "Row " + i + ": " + sb);
}
}
解决方案
图片加载的内存占用
不同dpi文件夹对图片内存的影响
文件夹 | 对应dpi | bitmap width | height | size | 倍数 |
---|---|---|---|---|---|
nodpi | 1920 | 1080 | 8294400 | 1 | |
xxxhdpi | 640 | 1320 | 743 | 3923040 | 0.47 |
xxhdpi | 480 | 1760 | 990 | 6969600 | 0.84 |
xhdpi | 320 | 2640 | 1485 | 15681600 | 1.89 |
mdpi | 160 | 5280 | 2970 | 62726400 | 7.56 |
![图片加载 640?wx_fmt=jpeg](https://i-blog.csdnimg.cn/blog_migrate/7da132319b301e6acdcf6b45718e3172.jpeg)
使用图片的建议
RGB565
除了图片资源的文件夹,加载图片时使用的色彩模式也影响了Bitmap大小。ARGB8888使用了32bit,所以一个像素需要4byte;RGB565使用了16bit,一个像素只需要2byte
但是因为RGB565少了alpha通道,对有透明度的图片显示有问题,而且显示效果上还是有些区别,所以并不建议修改这个属性,只是在对内存有严格要求的场景下可以作为特殊手段进行优化
ProGuard对内存的影响
压缩代码和资源
内存碎片
![Overview of memory management 640?wx_fmt=jpeg](https://i-blog.csdnimg.cn/blog_migrate/68cb1b87f1017ab20fc65d7efdd77b17.jpeg)
Davik的内存回收算法不能移动对象,所以会造成一个小对象占据整个内存页,产生内存碎片
而ART虚拟机的可以在GC时对内存空间进行整理,随着5.0以上系统的占有率逐渐提升,内存碎片造成的内存消耗可以不必过于关心
其他内存问题
Manage your app's memory
看完本文有收获?请转发分享给更多人
我们的知识星球第三期开期了,已达到1100人了,能连续做三期已很不容易了,有很多老用户续期,目前续期率达到50%,说明了大家对我们的知识星球还是很认可的,欢迎大家加入尽早我们的知识星球,更多星球信息参见:
说两件事
微信扫描或者点击上方二维码领取的Android \ Python的\ AI \的Java等高级进阶资源
更多学习资料点击下面的“阅读原文 ”获取
谢谢老板,点个好看↓