返回

Android 内存优化方式

发布时间:2022-09-18 09:12:05 325
# android# windows# 数据# 监控# 信息

1. Android 内存大小

//获取的是正常情况下 app 内存大小,我的小米 5s 是 256 M
activiyManager.getMemoryClass()

//在Android manifest 中设置 android:largeHeap="true" 之后 app 内存大小
activiyManager.getLargeMemoryClass();//Unit : M

完整代码 :

private  void calculate(){

StringBuilder stringBuilder = new StringBuilder();

ActivityManager activiyManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);

int memClass = activiyManager.getMemoryClass();// Unit : M

//Application : mainfest --> largeHeap --> not goog choice --> In most device, it has no difference. But in my MI 5S, it did work.

int LargememClass = activiyManager.getLargeMemoryClass();//Unit : M
stringBuilder.append("memClass : " + memClass + "\n");
stringBuilder.append("LargememClass : " + LargememClass + "\n");

info.setText(stringBuilder.toString());
Log.d("mooc", stringBuilder.toString());

在我的小米 5s 中, 数据 :

Android 内存优化方式_ooc

2. Android 内存管理方式

2.1 Android 系统内存分配和回收方式

Android 的底层是 Linux,开发应用的框架层是 Java,一个 App 通常就是一个进程对应一个虚拟机

体验一下:

  • 记下你 app 的包名,我的 :​​package com.lizi.nativeandroid;​
  • deploy app to your device
  • windows 搜索栏 输入 cmd,找到Command Prompt,, 选择 Run as administartor

Android 内存优化方式_ooc_02

//进入 Android底层 Linux 系统命令,adb 需要配置环境变量
adb shell
//ps 查看系统里面进程的命令

在进程列表中根据包名找到自己 app 进程 :

Android 内存优化方式_ooc_03

它的 父进程 :

Android 内存优化方式_复用_04

查看 app 进程相关信息

//dumpsys meminfo packagename
dumpsys meminfo com.lizi.nativeandroid

重新部署了下项目, id 变了,请忽略

Android 内存优化方式_android_05

操作系统把内存分配给进程之后, 进程在 app 中分配内存

  • Dalvik Heap
  • Native Heap
  • apk

GC 只有在 Heap 剩余空间不够时才发出垃圾回收, 如果内存不够,申请 GC 回收的时候 GC 里面有很多对象,很对变量,要知道 GC 的时候也会占用 处理器的时间的。这种极端情况下, GC 会影响你 app 的响应。

GC 触发时, 所有的线程都会被暂停

2.2App 内存限制机制

每个 App 非配的最大内存限制,随不同设备而不同

吃内存大户 : 图片

2.3 切换应用时后台 App 清理机制、

Android 系统通过 分时复用 使多个应用可以同时运行, 当你使用你的 app 时,点击 back or home , 并没有完全销毁,只是在后台的缓存中,下次运行的时候,直接从后台掉出来,所以速度非常快。

App 切换时的 LRU Cache

LRU 算法 : 最近使用的排在最前,最少使用的可能被清理掉

清理的时候 发出 onTrimMemory() 回掉方法,这并不只在清理时回掉, 系统内存有变化的时候会发出相应的 onTrimMemory() 给各个应用。

代码 :

@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
Log.d("mooc", "level : "

2.4 监控内存的几种方法

2.4.1 代码监控

.getRuntime().totalMemory()*1.0f /(1024*1024);
Float freeMemory = Runtime.getRuntime().freeMemory()*1.0f /(1024*1024);
Float maxMemory = Runtime.getRuntime().maxMemory()*1.0f /(1024*1024);

stringBuilder.append("totalMemory : " + totalMemory + "\n");
stringBuilder.append("freeMemory : " + freeMemory + "\n");
stringBuilder.append("maxMemory : " + maxMemory + "\n");

Android 内存优化方式_ooc_06

25M 是系统分配的内存, 最大上限是 512M

2.4.2 Android Monitor | Android Profiler

2.4.3 Android Device Monitor

Android 内存优化方式_android_07

点击你的 app, 点击 Cause GC , 内存大小变化就会出来

Android 内存优化方式_android_08

3. App 内存优化方法

  • 数据结构优化
  • 对象复用
  • 避免内存泄漏

3.1 数据结构优化

3.1.1 频繁字符串拼接使用 StringBuilder

Talking is cheap, show me the code.

private int rowLength = 20;
private int length = 300;
private int [][] intMatrix = new int[rowLength][length];
private Random ran = new Random();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

findView();

calculate();

for (int i = 0; i < rowLength; i++) {
for (int j = 0; j < length; j++) {
intMatrix[i][j] = ran.nextInt();
}
}
}

findViewById(R.id.starjoin).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.d("mooc", "starjoin clicked !");
doJoin();
}
});

findViewById(R.id.starbld).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.d("mooc", "starbld clicked !");
doBld();
}
});

private void doBld() {
StringBuilder rowStr = new StringBuilder();
Log.d("mooc", "doBld start : ");
for (int i = 0; i < rowLength; i++) {
for (int j = 0; j < length; j++) {
rowStr.append(intMatrix[i][j]);
rowStr.append(",");
}
Log.d("mooc", "doBld rowStr : " + i);
}
Log.d("mooc", "doBld rowStr : " + rowStr.toString().length());
}

private void doJoin() {
String rowStr = "";
Log.d("mooc", "doJoin start : ");
for (int i = 0; i < rowLength; i++) {
for (int j = 0; j < length; j++) {
rowStr = rowStr + intMatrix[i][j];
rowStr = rowStr + ",";
}
Log.d("mooc", "doJoin rowStr : " + i);
}
Log.d("mooc", "doJoin rowStr : "

当调用 doJoin(),性能 3S:

12-03 20:22:08.322 10917-10917/com.lizi.nativeandroid D/mooc: starjoin clicked !
12-03 20:22:08.322 10917-10917/com.lizi.nativeandroid D/mooc: doJoin start :
12-03 20:22:08.334 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 0
12-03 20:22:08.355 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 1
12-03 20:22:08.406 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 2
12-03 20:22:08.465 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 3
12-03 20:22:08.542 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 4
12-03 20:22:08.680 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 5
12-03 20:22:08.794 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 6
12-03 20:22:08.926 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 7
12-03 20:22:09.060 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 8
12-03 20:22:09.222 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 9
12-03 20:22:09.427 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 10
12-03 20:22:09.609 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 11
12-03 20:22:09.791 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 12
12-03 20:22:10.035 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 13
12-03 20:22:10.285 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 14
12-03 20:22:10.514 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 15
12-03 20:22:10.781 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 16
12-03 20:22:11.089 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 17
12-03 20:22:11.410 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 18
12-03 20:22:11.801 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 19
12-03 20:22:11.801 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 65928
12-03 20:22:11.802 10917-10917/com.lizi.nativeandroid I/Choreographer: Skipped 208 frames! The application may be doing too much work on its main thread.
12-03 20:22:26.867 10917-10917/com.lizi.nativeandroid D/mooc: level : 20

当调用 doBld(),性能 2 ms:

12-03 20:28:40.110 10917-10917/com.lizi.nativeandroid D/mooc: starbld clicked !
12-03 20:28:40.111 10917-10917/com.lizi.nativeandroid D/mooc: doBld start :
12-03 20:28:40.111 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 0
12-03 20:28:40.111 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 1
12-03 20:28:40.111 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 2
12-03 20:28:40.111 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 3
12-03 20:28:40.111 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 4
12-03 20:28:40.111 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 5
12-03 20:28:40.111 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 6
12-03 20:28:40.111 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 7
12-03 20:28:40.111 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 8
12-03 20:28:40.112 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 9
12-03 20:28:40.112 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 10
12-03 20:28:40.112 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 11
12-03 20:28:40.112 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 12
12-03 20:28:40.112 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 13
12-03 20:28:40.112 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 14
12-03 20:28:40.112 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 15
12-03 20:28:40.112 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 16
12-03 20:28:40.112 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 17
12-03 20:28:40.112 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 18
12-03 20:28:40.112 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 19
12-03 20:28:40.112 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 65928

3.1.2 ArrayMap 、SparseArray 替换 HashMap

  • 内存使用更少
  • 数据比较多的时候效率比较高
  • 使用起来和 HashMap 用法一致

3.1.3 内存抖动

代码 :

private int rowLength2 = 10;
private int length2 = 420000;
private void doChurn(){
Log.d("mooc", "doChurn start : ");
for (int i = 0; i < rowLength2; i++) {
//重点,变量放在这里,每次重新一行赋值的时候,这里又有新的变量,上一行的变量就废弃,GC
//优化,变量放在脑袋上的循环外面重复使用就可以了
String[] strMatrix = new String[length2];
for (int j = 0; j < length2; j++) {
//内存抖动原因:大量字符串占用空间 --> 420000
strMatrix[j] = String.valueOf(ran.nextDouble());
}
Log.d("mooc", "doChurn strMatrix : " + i);
}
Log.d("mooc", "doChurn strMatrix end : "

Android 内存优化方式_ooc_09

3.1.4 再小的 Class 耗费 0.5 kb

3.1.5 HashMap 一个 entry 需要额外占用 32B

3.2 对象复用

  • 复用系统自带的资源
  • ListView/GridView 的 ConvertView 复用
  • 避免在 onDraw 方法中执行对象的创建

3.3 避免内存泄漏

由于代码瑕疵,导致这块内存,虽然停止不用了,但是依然被其它东西引用这,使得 GC 没法对它回收

内存泄漏会导致剩余可用 Heap 越来越少,频繁触发 GC

4. OOM 问题优化

4.1 OOM 问题分析

Android 内存有限,展示图片容易OOM –> =-= | o.o | T_T

4.2 强引用、软引用的意义

private String strongRef;
private SoftReference softRef;

strongRef = String.valueOf(Math.random());
softRef = new SoftReference(String.valueOf(Math.random()));

场景 :

变量定义在 Activity 中,生命周期和 Activity 同步,Activity 存活期间这个变量所保存的内存空间不会被释放


强引用 : 在它的生命周期里它的内存空间不会被回收

软引用 : 在它的生命周期里它的内存空间 只要是内存不够, GC 可以把它回收掉

4.3 优化 OOM 问题的方法

  • 注意临时 BItmap 对象的及时回收 -> 置空| .recyle()
  • 注意 BItmap 的浪费
  • Try catch 某些大内存非配的操作
  • 加载 Bitmap :缩放比例、解码格式、局部加载 (解决绝大部分)

参考链接 : ​​https://www.imooc.com/video/13672​​

 

特别声明:以上内容(图片及文字)均为互联网收集或者用户上传发布,本站仅提供信息存储服务!如有侵权或有涉及法律问题请联系我们。
举报
评论区(0)
按点赞数排序
用户头像
精选文章
thumb 中国研究员首次曝光美国国安局顶级后门—“方程式组织”
thumb 俄乌线上战争,网络攻击弥漫着数字硝烟
thumb 从网络安全角度了解俄罗斯入侵乌克兰的相关事件时间线