当前位置: 首页 > news >正文

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

相关文章:

android内存管理机制概览

关于作者:CSDN内容合伙人、技术专家, 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 ,擅长java后端、移动开发、人工智能等,希望大家多多支持。 目录 一、导读二、概览三、相关概念3.1 垃圾回收3.2 应用内存的分配与回…...

下载MySQL Connector/C++

MySQL :: Download Connector/C...

ai gpt 鸡皮剔提问技巧

请将如下AB两组信息逐个匹配上的进行同类归类,用json格式输出: A:苹果 电脑 汽车 B: 猕猴桃 笔记本 根据你的要求,逐个匹配 A 组和 B 组的元素,并以 JSON 格式输出同类的归类信息: json { "匹配信息"…...

详谈 springboot整合shiro

背景: 本章将进一步的落地实践学习,在springboot中如何去整合shrio,整个过程步骤有个清晰的了解。 利用Shiro进行登录认证主要步骤: 1. 添加依赖:首先,在pom.xml文件中添加Spring Boot和Shiro的相关依赖…...

备忘录模式(Memento)

备忘录模式(Memento Pattern)是一种行为型设计模式,允许在不破坏封装的前提下捕获并保存一个对象的内部状态,以便在以后可以将该对象恢复到原先保存的状态。 备忘录模式通常涉及以下几个角色: 发起人(Originator):创建一个含有其当前状态的备忘录对象,并可以使用备忘录…...

【RocketMQ每日一问】consumeGroup心跳内容是什么样的?

消费者组:消费者所在的消费者组名称。这个信息用于确保同一个消费者组内的消费者不会重复地消费相同的消息。MessageModel:消息模型,可能的值为集群消费或广播消费。ConsumeType:消费类型,可能的值有"主动消费&qu…...

yolov5知识蒸馏

参考代码:https://github.com/Adlik/yolov5 https://cloud.tencent.com/developer/article/2160509 yolov5间的模型蒸馏,相同结构的。 配置参数 parser.add_argument(--t_weights, typestr, default./weights/yolov5s.pt,helpinitial teacher model wei…...

HUAWEI华为笔记本电脑MateBook D 14 2022款 i5 集显 非触屏(NbDE-WFH9)原装出厂Windows11系统21H2

链接:https://pan.baidu.com/s/1-tCCFwZ0RggXtbWYBVyhFg?pwdmcgv 提取码:mcgv 华为MageBookD14原厂WIN11系统自带所有驱动、出厂状态主题壁纸、Office办公软件、华为电脑管家、华为应用市场等预装软件程序 文件格式:esd/wim/swm 安装方式…...

微服务-springcloud(eureka实践, nacos实践)

Spring 体系图 版本关系 eureka 实践 1 父工程依赖 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.6.14</version> </parent> <dependencyManage…...

Hadoop入门学习笔记——五、在虚拟机中部署Hive

视频课程地址&#xff1a;https://www.bilibili.com/video/BV1WY4y197g7 课程资料链接&#xff1a;https://pan.baidu.com/s/15KpnWeKpvExpKmOC8xjmtQ?pwd5ay8 Hadoop入门学习笔记&#xff08;汇总&#xff09; 目录 五、在虚拟机中部署Hive5.1. 在node1虚拟机安装MySQL5.2.…...

用Nest 实现大文件分片上传,加速工作效率神器

文件上传是常见需求&#xff0c;只要指定 content-type 为 multipart/form-data&#xff0c;内容就会以这种格式被传递到服务端&#xff1a; 服务端再按照 multipart/form-data 的格式提取数据&#xff0c;就能拿到其中的文件。 但当文件很大的时候&#xff0c;事情就变得不一样…...

将ncnn及opencv的mat存储成bin文件的方法

利用fstream&#xff0c;将ncnn及opencv的mat存储成bin文件。 ncnn::Mat to bin std::ios::binary标志指示文件以二进制模式进行读写&#xff0c; std::ofstream file("output_x86.bin", std::ios::binary); 将input_mat中的宽、高和通道数分别赋值给width、heig…...

dpdk原理概述及核心源码剖析

dpdk原理 1、操作系统、计算机网络诞生已经几十年了&#xff0c;部分功能不再能满足现在的业务需求。如果对操作系统做更改&#xff0c;成本非常高&#xff0c;所以部分问题是在应用层想办法解决的&#xff0c;比如前面介绍的协程、quic等&#xff0c;都是在应用层重新开发的框…...

VTK+QT配置(VS)

先根据vtk配置这个博客配置基本环境 然后把这个dll文件从VTK的designer目录复制到qt的对应目录里 记得这里是debug版本&#xff0c;你也可以配置release都一样的步骤&#xff0c;然后建立一个qt项目&#xff0c;接着配置包含目录&#xff0c;库目录&#xff0c;链接输入&…...

5G边缘计算:解密边缘计算的魔力

引言 你是否曾想过&#xff0c;网络可以更贴心、更智能地为我们提供服务&#xff1f;5G边缘计算就像是网络的小助手&#xff0c;时刻待命在你身边&#xff0c;让数字生活变得更加便捷。 什么是5G边缘计算&#xff1f; 想象一下&#xff0c;边缘计算就像是在离你最近的一层“云…...

Sentinel 流量治理组件教程

前言 官网首页&#xff1a;home | Sentinel (sentinelguard.io) 随着微服务的流行&#xff0c;服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件&#xff0c;主要以流量为切入点&#xff0c;从流量路由、流量控制、流量整形…...

C语言第五十九弹---介绍说明内存函数memcmp

使用C语言介绍说明内存函数memcmp memcmp是C语言标准库中的一个函数&#xff0c;用于比较两个内存区域的内容是否相同。 源代码&#xff1a; int memcmp(const void* ptr1, const void* ptr2, size_t num);ptr1和ptr2分别是要比较的两个内存区域的指针&#xff0c;num是要比较…...

jar混淆,防止反编译,Allatori工具混淆jar包

文章目录 Allatori工具简介下载解压配置config.xml注意事项 Allatori工具简介 官网地址&#xff1a;https://allatori.com/ Allatori不仅混淆了代码&#xff0c;还最大限度地减小了应用程序的大小&#xff0c;提高了速度&#xff0c;同时除了你和你的团队之外&#xff0c;任何人…...

linux中批量将HEIC转jpg

苹果目前已大量使用HEIC格式的照片&#xff0c;虽然上传到Windows系统的时候是会自动转为jpg的&#xff0c;但也经常会在很多场景中保留了HEIC格式&#xff0c;前两天就收到了一大堆HEIC文件&#xff0c;window10里都打不开&#xff0c;照片的插件是需要付费下载的&#xff0c;…...

听GPT 讲Rust源代码--src/tools(25)

File: rust/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs 在Rust源代码中&#xff0c;suspicious_command_arg_space.rs文件位于clippy_lints工具包的methods目录下&#xff0c;用于实现Clippy lint SUSPICIOUS_COMMAND_ARG_SPACE。 Clippy是Ru…...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接&#xff0c;私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

Cesium1.95中高性能加载1500个点

一、基本方式&#xff1a; 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件

在选煤厂、化工厂、钢铁厂等过程生产型企业&#xff0c;其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进&#xff0c;需提前预防假检、错检、漏检&#xff0c;推动智慧生产运维系统数据的流动和现场赋能应用。同时&#xff0c;…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)

0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述&#xff0c;后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作&#xff0c;其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

【HTTP三个基础问题】

面试官您好&#xff01;HTTP是超文本传输协议&#xff0c;是互联网上客户端和服务器之间传输超文本数据&#xff08;比如文字、图片、音频、视频等&#xff09;的核心协议&#xff0c;当前互联网应用最广泛的版本是HTTP1.1&#xff0c;它基于经典的C/S模型&#xff0c;也就是客…...

实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路 在Android中&#xff0c;可以通过监听键盘的显示和隐藏事件&#xff0c;动态调整弹窗的位置。关键点在于获取键盘高度&#xff0c;并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

使用 SymPy 进行向量和矩阵的高级操作

在科学计算和工程领域&#xff0c;向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能&#xff0c;能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作&#xff0c;并通过具体…...

Typeerror: cannot read properties of undefined (reading ‘XXX‘)

最近需要在离线机器上运行软件&#xff0c;所以得把软件用docker打包起来&#xff0c;大部分功能都没问题&#xff0c;出了一个奇怪的事情。同样的代码&#xff0c;在本机上用vscode可以运行起来&#xff0c;但是打包之后在docker里出现了问题。使用的是dialog组件&#xff0c;…...

React---day11

14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store&#xff1a; 我们在使用异步的时候理应是要使用中间件的&#xff0c;但是configureStore 已经自动集成了 redux-thunk&#xff0c;注意action里面要返回函数 import { configureS…...