Skip to content

Latest commit

 

History

History
111 lines (64 loc) · 3.8 KB

Android基础-内存治理.md

File metadata and controls

111 lines (64 loc) · 3.8 KB

你做过哪些内存治理相关的工作?要治理哪些问题?

OOM:所申请的内存 > 可分配内存 - 已分配内存

内存抖动:申请的内存过大 -> 创建了大型实例或短时间内创建了非常多的小实例

内存泄漏:实例的生命周期结束后依然存在GCRoot的引用链条上,垃圾回收器依然认为实例有用

内存治理三板斧:回收 压缩 复用

  1. 堆内存溢出

    1. 垃圾回收 STW

      STW:Stop the world:GC的同时暂停一切用户线程

      • 并行、并发回收
      • 缩小回收范围
    2. 内存分配 OOM

    解决内存抖动、内存泄露

  2. 线程数超限

    线程数超限 OOM 消灭野线程

  3. FD泄漏

    FD 也叫文件句柄,在 Linux 里,文件、目录、块设备、字符设备、管道等都被抽象成了文件,所以在调用这些文件的时候,都会返回一个 FD。

    FD数超限 OOM

    FD泄漏原因是FD没有及时释放:文件未正常关闭、I/O未正常关闭、Cursor未正常关闭

    治理思路:及时关闭I/O操作、及时关闭数据库和Cursor、及时释放HandlerThread

Bitmap 内存治理:三级缓存

  • 能控制内存总占用
  • 避免重复创建 Bitmap

Activity 内存泄漏可能原因

  • Activity 被静态变量或单例所持有
  • 被其他长生命周期实例持有
  • 注意:尽量别作为参数传递Activity
  • 注意:Activity 生命周期结束时取消异步任务

OOM:pthread_create failed.

  • 系统分配线程栈失败
    • 系统内存不足的时候启动线程
    • 进程内运行的线程数超过了系统的限制,需要控制并发线程数来解决
    • 使用线程池或 Kotlin 协程

一些好的编码习惯

  • 谨慎使用static、顶层变量和单例
  • 关注内部类的生命周期
  • 注册与反注册要成对出现
  • 需要context的情况尽量使用Application Context
  • 酌情使用枚举
  • 尽量避免自动拆装箱
  • 避免过度的页面绘制
  • 及时关闭I/O和Cursor
  • 及时释放HandlerThread

常用的内存优化工具

举例实际解决过的项目中的内存问题

如何实现线上性能监控?解决线上内存问题

  • Android Profiler:Android Studio 内置的 Profiler 工具可以用于监控内存使用情况,但它主要用于开发和测试阶段,而非线上环境。
  • LeakCanary:一个开源库,用于检测 Android 应用中的内存泄漏。它可以在开发过程中使用,也可以配置为在线上环境中运行,以便捕获并报告内存泄漏。
  • MAT (Memory Analyzer Tool):一个强大的 Java 堆分析工具,用于分析大型堆转储。它可以帮助你找到内存泄漏和减少内存占用。

Java 堆内存和栈内存有什么区别?

  1. 存储内容

    堆内存:主要用于存储 Java 程序中创建的对象。

    栈内存:存储基本类型的变量(如 int、float 等)和对象引用变量的实际值,这些变量通常是方法的局部变量和方法调用的参数。

  2. 内存管理

    堆内存:由 Java 垃圾回收器管理。

    栈内存:遵循后进先出(LIFO)的原则进行内存管理。当方法结束时,方法中的所有栈帧都会自动释放。

  3. 生命周期

    堆内存:生命周期较长,它随着应用程序的运行而存在。

    栈内存:生命周期较短,只在单个方法调用中存在。

  4. 线程安全

    堆内存:由于可能被多个线程共享,因此访问堆内存通常涉及到线程安全性问题。

    栈内存:每个线程都有自己的栈内存,因此从线程安全的角度来看,栈内存是安全的。

  5. 内存空间大小

    堆内存:通常有较大的空间,可以动态扩展。

    栈内存:相对较小,有严格的物理限制。