| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 移动开发 -> Android内存管理 -> 正文阅读 |
|
[移动开发]Android内存管理 |
转载请注明出处:https://blog.csdn.net/mythmayor/article/details/123117007前言在Android或Java中,我们一般不用担心内存管理,这是因为Java虚拟机(JVM:Java Virtual Machine)存在垃圾回收机制(GC:Garbage Collection),垃圾回收器会对内存进行管理。相比于其它语言(例如C语言),会要求主动释放申请的内存,所以在编程的时候需要考虑内存申请和内存释放的时机。Java GC的存在从一定程度上减少了我们的工作量,但带来的后果就是很多时候我们会滥用内存,比如说申请了一块较大的内存,很少会去关注这块内存何时释放以及如何释放,从而导致应用占用的内存越来越大,甚至到最后产生了内存溢出(OOM:Out Of Memory),进而引发程序崩溃。所以,关注内存变化并了解一些内存优化和监控是有必要的。 一、内存概述1.JVM内存结构上图描述了HelloWorld.java文件被JVM加载到内存中的过程:首先需要经过编译器编译,生成HelloWorld.class 字节码文件,然后通过ClassLoader(类加载器)将HelloWorld.class加载到JVM的内存中。JVM中的内存可以划分为若干个不同的数据区域,主要分为:程序计数器、虚拟机栈、本地方法栈、堆、方法区。 程序计数器(Program Counter Register)Java程序是多线程的,CPU可以在多个线程中分配执行时间片段。当某一个线程被CPU挂起时,需要记录代码已经执行到的位置,方便CPU重新执行此线程时,知道从哪行指令开始执行。这就是程序计数器的作用。 程序计数器是虚拟机中一块较小的内存空间,主要用于记录当前线程执行的位置。 虚拟机栈
这里说到的栈就是虚拟机栈。 虚拟机栈是线程私有的,与线程的生命周期同步。在Java虚拟机规范中,对这个区域规定了两种异常情况:
虚拟机栈的初衷是用来描述Java方法执行的内存模型,每个方法被执行的时候,JVM都会在虚拟机栈中创建一个栈帧(栈帧(Stack Frame)是用于支持虚拟机进行方法调用和方法执行的数据结构,每一个线程在执行某个方法时,都会为这个方法创建一个栈帧。一个线程包含多个栈帧,而每个栈帧内部包含局部变量表、操作数栈、动态连接、返回地址等)。 本地方法栈本地方法栈和上面介绍的虚拟栈基本相同,只不过是针对本地(native)方法。在开发中如果涉及JNI可能接触本地方法栈多一些,在有些虚拟机的实现中已经将两个合二为一了(比如HotSpot)。 堆Java堆(Heap)是JVM所管理的内存中最大的一块,该区域唯一目的就是存放对象实例,几乎所有对象的实例都在堆里面分配,因此它也是Java垃圾收集器(GC)管理的主要区域,有时候也叫作“GC堆”。同时它也是所有线程共享的内存区域,因此被分配在此区域的对象如果被多个线程访问的话,需要考虑线程安全问题。 方法区方法区(MethodArea)也是JVM规范里规定的一块运行时数据区。方法区主要是存储已经被JVM加载的类信息(版本、字段、方法、接口)、常量、静态变量、即时编译器编译后的代码和数据。该区域同堆一样,也是被各个线程共享的内存区域。 2.Android中内存分配每一个Android设备都会有不同的RAM总大小与可用空间,因此不同设备为App提供了不同大小的内存限制(这里的内存主要指的是堆内存)。如果你觉得分配的内存不够用,还可以通过在清单文件中开启android:largeHeap="true"来获取更多内存。然而,能够获取更大内存的设计本意是为了一小部分会消耗大量RAM的应用(例如一个大图片的编辑应用),所以不要轻易地因为需要使用大量内存而去申请largeHeap,只有当你清楚的知道哪里会使用大量的内存并且为什么这些内存必须被保留时再去使用largeHeap。因为使用额外的内存会影响系统整体的用户体验,并且会使得GC的每次运行时间更长。在切换任务时,系统的性能会大打折扣。另外, largeHeap并不一定能够获取到更大的内存。在某些有严格限制的机器上,largeHeap的大小和通常的heapSize是一样的。因此即使你申请了largeHeap,你还是应该通过执行getMemoryClass()来检查实际获取到的内存大小。 获取应用内存大小:
二、内存优化方案我们在做内存优化时,无非有两个方向:
1.内存溢出(OOM)通常在排查内存溢出相关的问题时,可以从以下几个方面入手:
总之,内存溢出的产生都是由于App申请的内存超过了应用的内存上限,这是JVM就会抛出OutOfMemoryError,从而导致应用程序的崩溃。解决内存溢出的方法主要有:(1)使用LruCache对图片进行缓存;(2)避免在for循环中创建对象;(3)加载大图片时使用图片压缩、图片裁剪等技术;(4)及时释放不再使用的对象占用的内存;(5)不要将Context和View存储在静态变量中。(6)使用内存监控机制,例如在Application或Activity中监听onTrimMemory(int level)方法的调用,根据不同的内存状态释放无用资源或者清除图片缓存等;(7)内存泄漏同样是内存溢出的关键因素之一,可针对内存泄漏问题进行分析并处理。 2.内存泄漏(Memory Leak)通常在排查内存泄漏相关的问题时,可以从以下几个方面入手:
使用到的工具有:LeakCanary、Profiler等。 三、低内存监控方案Android中提供了两个低内存监控方法:onLowMemory()与onTrimMemory(int level)。可以通过这两个方法判断当前是否是低内存的状态,并且根据不同的情况释放自身内存,以避免应用程序被系统杀掉,提高应用程序的用户体验。 1.onLowMemory()
onLowMemory()方法定义在ComponentCallbacks接口中,实现该接口的有Application、Activity、Fragment、Service、ContentProvider。当整个系统运行内存不足时,就会被调用。此时为了避免程序崩溃,可以采取一些措施,例如在Application中清除缓存,在Activity和Fragment中释放无用资源(例如Bitmap、数组、控件资源等)等。 根据Google官方的说法,该方法是在后台进程都被杀死时调用,此时面临的局面是下一步很有可能会将当前的前台进程杀死,但是该方法没有确切的调用时间,只是用于Android旧版本低内存监控。Android4.0以后可以直接用onTrimMemory(int level)方法来监听内存状态,并且onLowMemory()调用时可以理解为达到了onTrimMemory(int level)方法的ComponentCallbacks2.TRIM_MEMORY_COMPLETE级别,即最高级别。 在实际测试中并未监测到onLowMemory()方法的调用,只监测到onTrimMemory(int level)方法的调用,并且onTrimMemory(int level)方法的level达到最高级别时也未调用onLowMemory()方法。 2.onTrimMemory(int level)
onTrimMemory(int level)是Android4.0提供的API(Android4.0以下的版本中使用onLowMemory()方法),方法定义在ComponentCallbacks2接口中,实现该接口的有Application、Activity、Fragment、Service、ContentProvider。该方法和onLowMemory()方法类似,当整个系统运行内存不足时,就会被调用,不过onTrimMemory(int level)方法中多了当前内存级别(水平)情况,系统会根据不同的内存状态,来响应不同的内存释放策略,使用起来更加灵活,场景也更加丰富。 onTrimMemory(int level)方法的内存级别:
3.onLowMemory()与onTrimMemory(int level)触发时机总结(1)onLowMemory()被回调时,已经没有后台进程;而onTrimMemory(int level)被回调时,还有后台进程。 (3)通过一键清理后,onLowMemory()不会被触发,而onTrimMemory(int level)会被触发一次。 (4)在Application、 Activity、Fragement、Service、ContentProvider中都可以重写回调方法,对onLowMemory()/onTrimMemory(int level)进行回调,在回调方法中实现资源释放。 4.使用场景及优化策略通常在架构阶段就要考虑清楚,我们有哪些东西是要常驻内存的,有哪些是伴随界面存在的。一般情况下,有下面几种资源需要进行释放:
|
|
移动开发 最新文章 |
Vue3装载axios和element-ui |
android adb cmd |
【xcode】Xcode常用快捷键与技巧 |
Android开发中的线程池使用 |
Java 和 Android 的 Base64 |
Android 测试文字编码格式 |
微信小程序支付 |
安卓权限记录 |
知乎之自动养号 |
【Android Jetpack】DataStore |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 15:35:18- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |