android内存管理机制概览

关于作者:CSDN内容合伙人、技术专家, 从零开始做日活千万级APP。
专注于分享各领域原创系列文章 ,擅长java后端、移动开发、人工智能等,希望大家多多支持。

目录

  • 一、导读
  • 二、概览
  • 三、相关概念
    • 3.1 垃圾回收
    • 3.2 应用内存的分配与回收
    • 3.3 切换应用
    • 3.4 内存不足管理
      • 内核交换守护程序
      • 低内存终止守护程序
  • 四、主动管理应用内存
    • 4.1 内存监控
      • 通过命令行查看内存占用情况
      • 通过Android Studio的Profiler工具
      • 通过代码
    • 4.2 释放内存
      • ComponentCallbacks2 接口
      • application中复写onTrimMemory()、onLowMemory()等方法
    • 4.3 查看应该使用多少内存
    • 4.4 写在后面
      • java 内存分配、内存回收算法
      • android dalvik 与 art区别
    • 4.5 相关工具
    • 内存压力测试
  • 五、 推荐阅读

在这里插入图片描述

一、导读

我们继续总结学习基础知识,温故知新。

本文主要描述Android中的内存管理及java中的内存管理相关知识点。

二、概览

Android内存优化是性能优化中很重要的一部分,比如内存溢出(OOM),这些都跟内存息息相关,所以,我们要掌握一些相关知识。

Android 运行时 (ART) 和 Dalvik 虚拟机使用分页和内存映射来管理内存。
这意味着应用修改的任何内存,无论修改的方式是分配新对象还是轻触内存映射的页面,都会一直驻留在 RAM 中,并且无法换出。
若要从应用中释放内存,只能释放应用保留的对象引用,使内存可供垃圾回收器回收。
这种情况有一个例外:对于任何未经修改的内存映射文件(如代码),如果系统想要在其他位置使用其内存,可将其从 RAM 中换出。

Android 设备包含三种不同类型的内存:RAM、zRAM 和存储器。

在这里插入图片描述

  • RAM 是最快的内存类型,但其大小通常有限。
  • zRAM 是用于交换空间的 RAM 分区。所有数据在放入 zRAM 时都会进行压缩,然后在从 zRAM 向外复制时进行解压缩。这部分 RAM 会随着页面进出 zRAM 而增大或缩小。
  • storage 中包含所有持久性数据(例如文件系统等),以及为所有应用、库和平台添加的对象代码。存储器比另外两种内存的容量大得多。

待申请的内存大于系统分配给应用的剩余内存

三、相关概念

3.1 垃圾回收

ART 或 Dalvik 虚拟机之类的受管内存环境会跟踪每次内存分配。一旦确定程序不再使用某块内存,它就会将该内存重新释放到堆中,无需程序员进行任何干预。
垃圾回收有两个目标:一是查找将来无法访问的数据对象,二是回收这些对象使用的资源。

我们在之前的文章Jvm堆分类中介绍过,堆内存分为三部分: 新生代,老年代,永久代(元空间)。
在Android 的内存堆亦是分代的,堆的每一代对相应对象可占用的内存量都有其自身的专用上限。每当一代开始填满时,系统便会执行垃圾回收事件以释放内存。
垃圾回收的持续时间取决于它回收的是哪一代对象以及每一代有多少个活动对象。

尽管垃圾回收速度非常快,但仍会影响应用的性能。通常情况下,您无法从代码中控制何时发生垃圾回收事件。系统有一套专门确定何时执行垃圾回收的标准。
当条件满足时,系统会停止执行进程并开始垃圾回收。如果在动画或音乐播放等密集型处理循环过程中发生垃圾回收,可能会增加处理时间,
进而可能会导致应用中的代码执行超出建议的 16 毫秒阈值,无法实现高效、流畅的帧渲染。

3.2 应用内存的分配与回收

每个应用Dalvik 堆大小可以根据需要增长,但不能超过系统为每个应用定义的上限。不同设备的确切堆大小上限取决于设备的总体可用 RAM 大小
我们可以通过代码来检查可用空间

ActivityManager.getMemoryClass() 查询当前应用的Heap Size

逻辑上讲的Heap Size和实际物理意义上使用的内存大小是不对等的,Proportional Set Size(PSS)记录了应用程序自身占用以及与其他进程进行共享的内存。
Android系统并不会对Heap中空闲内存区域做碎片整理。系统仅仅会在新的内存分配之前判断Heap的尾端剩余空间是否足够,如果空间不够会触发GC操作,从而腾出更多空闲的内存空间

在Android中存在大量的共享内存,如Zygote进程,静态数据等

3.3 切换应用

当用户在应用之间切换时,Android 会将非前台应用保留在缓存中。非前台应用就是指用户看不到或未运行前台服务(如音乐播放)的应用。
例如,当用户首次启动某个应用时,系统会为其创建一个进程;但是当用户离开此应用时,该进程不会退出。系统会将该进程保留在缓存中。如果用户稍后返回该应用,系统会重复使用该进程,从而加快应用切换速度。

如果您的应用具有缓存的进程且保留了目前不需要的资源,那么即使用户未使用您的应用,它也会影响系统的整体性能。当系统资源(如内存)不足时,
它将会终止缓存中的进程。系统还会考虑终止占用最多内存的进程以释放 RAM。

3.4 内存不足管理

Android 有两种处理内存不足情况的主要机制:内核交换守护程序和低内存终止守护程序。

内核交换守护程序

内核交换守护程序 (kswapd) 是 Linux 内核的一部分,用于将已使用内存转换为可用内存。当设备上的可用内存不足时,该守护程序将变为活动状态。Linux 内核设有可用内存上下限阈值。
当可用内存降至下限阈值以下时,kswapd 开始回收内存。当可用内存达到上限阈值时,kswapd 停止回收内存。

低内存终止守护程序

很多时候,内核交换守护程序(kswapd) 不能为系统释放足够的内存。在这种情况下,系统会使用 onTrimMemory() 通知应用内存不足,应该减少其分配量。
如果这还不够,内核会开始终止进程以释放内存。它会使用低内存终止守护程序 (LMK) 来执行此操作。

LMK 使用一个名为 oom_adj_score 的“内存不足”分值来确定正在运行的进程的优先级,以此决定要终止的进程。最高得分的进程最先被终止。后台应用最先被终止,系统进程最后被终止。

四、主动管理应用内存

RAM 是一项宝贵资源,虽然 Android 运行时 (ART) 和 Dalvik 虚拟机都会定期执行垃圾回收任务,但这并不意味着可以忽略应用分配和释放内存的位置和时间。
您仍然需要避免引入内存泄漏问题(通常因在静态成员变量中保留对象引用而引起),并在适当时间(如生命周期回调所定义)释放所有 Reference 对象。

OOM有两个场景,一是内存真正不足,一是可用内存不足

4.1 内存监控

为了更好的使用内存,我们自己要对内存进行监控,内存监控的主要指标为:内存占用、OOM。我们可以用多种方式来查看内存占用情况:

通过命令行查看内存占用情况

adb shell dumpsys meminfo -a com.xxx
在这里插入图片描述

通过Android Studio的Profiler工具

通过代码

具体可参考 Memory Analyzer(MAT)分析内存 中hprof 文件准备,能获取到内存文件。

4.2 释放内存

在应用中,我们可以通过多种方式来处理系统内存不足

ComponentCallbacks2 接口

在 Activity 类(或其他地方)中实现 ComponentCallbacks2 接口,借助所提供的 onTrimMemory() 回调方法,然后释放对象

例如,您可以实现 onTrimMemory() 回调以响应与内存相关的不同事件,如下所示:

import android.content.ComponentCallbacks2;
// Other import statements ...public class MainActivity extends AppCompatActivityimplements ComponentCallbacks2 {// Other activity code .../*** Release memory when the UI becomes hidden or when system resources become low.* @param level the memory-related event that was raised.*/public void onTrimMemory(int level) {// Determine which lifecycle or system event was raised.switch (level) {case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:/*Release any UI objects that currently hold memory.The user interface has moved to the background.*/break;case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE:case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:/*Release any memory that your app doesn't need to run.The device is running low on memory while the app is running.The event raised indicates the severity of the memory-related event.If the event is TRIM_MEMORY_RUNNING_CRITICAL, then the system willbegin killing background processes.*/break;case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND:case ComponentCallbacks2.TRIM_MEMORY_MODERATE:case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:/*Release as much memory as the process can.The app is on the LRU list and the system is running low on memory.The event raised indicates where the app sits within the LRU list.If the event is TRIM_MEMORY_COMPLETE, the process will be one ofthe first to be terminated.*/break;default:/*Release any non-critical data structures.The app received an unrecognized memory level valuefrom the system. Treat this as a generic low-memory message.*/break;}}
}

application中复写onTrimMemory()、onLowMemory()等方法

4.3 查看应该使用多少内存

通过调用 getMemoryInfo() 向系统查询,其中会提供与设备当前的内存状态有关的信息,包括可用内存、总内存和内存阈值(如果内存用量达到此数值,系统就会开始终止进程)。
ActivityManager.MemoryInfo 对象还会公开一个简单的布尔值 lowMemory,您可以根据此值确定设备是否内存不足


// Get a MemoryInfo object for the device's current memory status.
private ActivityManager.MemoryInfo getAvailableMemory() {ActivityManager activityManager = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();activityManager.getMemoryInfo(memoryInfo);return memoryInfo;
}

4.4 写在后面

java 内存分配、内存回收算法

对于java的内存管理,我们要清楚的知道java的内存分配区域、以及内存回收算法,
掌握几种垃圾回收算法及思想、适配场景及优化演进的过程,常用的有:

标记-清除算法

  1. 标记出所有需要回收的对象
  2. 统一回收所有被标记的对象

要对每个区域进行标记,效率相对要低,而且会产生大量不连续的碎片,

复制算法

  1. 将整个内存划分为大小相等的两块,比如左右两边
  2. 一块内存(例如左边)用完后复制存活对象到另一块(例如右边)
  3. 再清理另一块内存(例如左边),使之连续

这样比较浪费内存,因为有一块区域始终是空的,准备用于复制用

标记-整理算法

  1. 对每个区域进行标记,标记出所有需要回收的对象
  2. 将存活的对象移动到一起
  3. 清理其余要回收的对象

分代收集算法

  1. 结合多种收集算法

android dalvik 与 art区别

android 是基于java语音的,但是仍然有自己的独特的改造,dalvik的垃圾回收算法是固定的,每个手机在系统确定好后就不会变化了,
而art的垃圾回收算法是在运行期间可以变化的,

4.5 相关工具

内存压力测试

stressapptest
压力应用测试 (stressapptest) 是一种内存接口测试,有助于创建真实的高负载场景,以测试应用在内存和硬件方面存在的各种限制。
由于能够定义时间和内存限制,因此通过该测试,您可以编写插桩,以便验证哪些现实情况会出现内存耗用量高的问题。
例如,使用以下命令集推送数据文件系统中的静态库,使其可执行,并在 990 MB 的情况下运行压力测试 20 秒:

    adb push stressapptest /data/local/tmp/adb shell chmod 777 /data/local/tmp/stressapptestadb shell /data/local/tmp/stressapptest -s 20 -M 990

可自行学习。

五、 推荐阅读

Java 专栏

SQL 专栏

数据结构与算法

Android学习专栏

ddd

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/299486.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

50个免费的 AI 工具,提升工作效率(附网址)

上次我们已经介绍了20个精选的提高工作效率的免费AI工具,但如果你觉得这些AI工具还不过瘾的话,想进一步成为职场中最了解AI的人,本文将汇总介绍免费最新的50个AI工具。 DeepSwap DeepSwap 是一个基于 AI 的工具,适用于想要制作令人…

内存之-LeakCanary

关于作者:CSDN内容合伙人、技术专家, 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 ,擅长java后端、移动开发、人工智能等,希望大家多多支持。 目录 一、导读二、概览三、使用四、原理分析4.1 自动初始化4.1.1 初始化…

改善OEE的关键:从反应性维护向预测性维护转变

科技的进步正在对企业的日常运营模式产生影响。许多制造企业已经采用了自动化生产流程,这不仅提高了产品质量,还简化了设备维护流程,并使得制造企业的设备维护方式从反应性维护转变为预测性维护。人们发现,设备维护方式的转变显著…

前端通过不同方式画等腰梯形

1.css画 说明&#xff1a;css画出倒梯形 <div class"outer-box"><div class"gradient_bg"></div></div> .outer-box{width: 50px;height: 50px;position: relative;//overflow: hidden; } /*使用transform属性后&#xff0c;梯形…

[kubernetes]Kube-APIServer

API Server API Server是什么 提供集群管理的REST API接口&#xff0c;包括认证授权、数据校验以及集群状态变更等提供其他模块之间的数据交互和通信的枢纽&#xff08;其他模块通过API Server查询或修改数据&#xff0c;只有API Server才直接操作etcd&#xff09; 访问控制…

统计学常见概率分布

1.离散型随机变量 E ( X ) ∑ i 1 n x i p i E(X)\sum_{i1}^{n}x_ip_i E(X)i1∑n​xi​pi​ D ( X ) σ 2 E ( X 2 ) − [ E ( X ) ] 2 D(X)\sigma^2E(X^2)-[E(X)]^2 D(X)σ2E(X2)−[E(X)]2 1.1 二项分布 n n n个相同试验&#xff1b;每次试验只有2个可能的结果&#xff1…

插入排序详解(C语言)

前言 插入排序是一种简单直观的排序算法&#xff0c;在小规模数据排序或部分有序的情况下插入排序的表现十分良好&#xff0c;今天我将带大家学习插入排序的使用。let’s go ! ! ! 插入排序 插入排序的基本思想是将待排序的序列分为已排序和未排序两部分。初始时&#xff0c…

介绍一个在线K8S练习平台

是不是有很多小伙伴想学习k8s&#xff0c;但是又没有机器去练习。使用自己的笔记本电脑或者主机只能搭建单机版本的k8s来练习。 现在福利来了&#xff0c;给大家介绍一个在线多节点k8s练习平台&#xff1a;Play with Kubernetes。 Play with Kubernetes 介绍 Play with Kube…

Modbus转Profinet网关解决设备通讯不稳的问题

通讯不稳定&#xff1a;表现为数据断断续续&#xff0c;多半是由于线路干扰、接口不匹配、程序不稳定、等原因造成。 解决方案&#xff1a;在原配电柜添加Modbus转Profinet网关&#xff08;XD-MDPN100/2000&#xff09;即可解决通迅该问题&#xff0c;Modbus转Profinet网关&…

isp代理/双isp代理/数据中心代理的区别?如何选择?

本文我们来详细科普一下几种不同的代理类型&#xff1a;isp代理/双isp代理/数据中心代理&#xff0c;了解他们的区别&#xff0c;选择更适合自己的代理类型。 在讲述这几种代理类型之前&#xff0c;我们先复习一下代理大类有哪几种。 一、机房代理和非机房代理 在做代理ip选…

Linux服务器流量监控、统计、限制、实时流量,按小时查询、按天数查询、按月数查询、按周数查询、查询TOP10等等各种纬度统计

Linux服务器流量监控、统计、限制、实时流量,按小时查询、按天数查询、按月数查询、按周数查询、查询TOP10等等各种纬度统计。 ServerStatus-V 是一个酷炫高逼格的云探针、云监控、服务器云监控、多服务器探针。使用方便,信息直观。ServerStatus-V 是 ServerStatus 中文版 项…

【Java动态代理如何实现】

✅Java动态代理如何实现 ✅JDK动态代理和Cglib动态代理的区别 ✅拓展知识仓✅静态代理和动态代理的区别✅动态代理的用途✅Spring AOP的实现方式&#x1f4d1;JDK 动态代理的代码段&#x1f4d1;Cglib动态代理的代码块 ✅注意事项&#xff1a; 在Java中&#xff0c;实现动态代理…