【Android 内存优化】内存抖动 ( 垃圾回收算法总结 | 分代收集算法补充 | 内存抖动排查 | 内存抖动操作 | 集合选择 )

简介: 【Android 内存优化】内存抖动 ( 垃圾回收算法总结 | 分代收集算法补充 | 内存抖动排查 | 内存抖动操作 | 集合选择 )

文章目录

一、 垃圾回收算法总结

二、 分代收集算法补充

三、 查看 Java 虚拟机

四、 获取 Android 应用可使用最大内存

五、 内存抖动标志

六、 排查内存抖动

七、 常见的造成内存抖动操作

八、 从内存优化角度选择集合





一、 垃圾回收算法总结


【Android 内存优化】垃圾回收算法 ( 内存优化总结 | 常见的内存泄漏场景 | GC 算法 | 标记清除算法 | 复制算法 | 标记压缩算法 ) 介绍了 标记清除算法 , 复制算法 , 标记压缩算法 , 三种垃圾回收算法 ;


【Android 内存优化】垃圾回收算法 ( 分代收集算法 | Serial 收集器 | ParNew 收集器 | Parallel Scavenge 收集器 | CMS 并发标记清除收集器 ) 博客中介绍了分代收集算法 , 并对常用的垃圾收集器进行了介绍 , 下面总结一下垃圾回收算法 , 与垃圾收集器 ;




1. 垃圾回收算法 :



① 标记清除算法 : 标记可回收的对象 , 之后将标记的对象回收 ; 内存碎片化 ;


② 复制算法 : 使用一半内存 , 当无法申请内存时 , 直接将有效对象拷贝到另一半内存中 ; 浪费内存 , 效率低下 ;


③ 标记压缩算法 : 标记回收内存对象 , 整理内存 ; 增加了开销 ;


④ 分代收集算法 : 将内存分为年轻代 , 老年代 , 持久代 , 三块区域 ; 不同生命周期的内存对象进行不同的管理 ;




2. 垃圾收集器总结 :



① Serial 收集器 : 年轻代 , 复制算法 , 单线程 GC , 暂停用户线程 ;


② ParNew 收集器 : 年轻代 , 复制算法 , 多线程 GC , 暂停用户线程 ;


③ Parallel Scavenge 收集器 : 年轻代 , 复制算法 , 多线程 GC , 暂停用户线程 ( 关注吞吐量 ) ;


④ CMS ( Concurrent Mark Sweep ) 并发标记清除收集器 ( 重点 ) : 老年代 , 标记-清除算法 , 多线程 GC , 与用户线程并发 ( 短时间暂停 ) ;


⑤ Parallel Old 收集器 : 老年代 , 标记整理算法 , 多线程 GC , 暂停用户线程 ;


⑥ Serial Old 收集器 : 老年代 , 标记整理算法 , 单线程 GC , 暂停用户线程 ;






二、 分代收集算法补充


【Android 内存优化】垃圾回收算法 ( 分代收集算法 | Serial 收集器 | ParNew 收集器 | Parallel Scavenge 收集器 | CMS 并发标记清除收集器 ) 一、 分代收集算法 章节对分代收集算法做了下简介 , 感觉没有描述清楚 , 再补充下 :



1. 主流垃圾回收算法 : JVM , DVM 都采用了 分代收集算法 , 将内存划分成不同的内存区域 , 不同的区域采用不同的垃圾收集算法 , 这是目前主流的 Java 虚拟机都在使用的垃圾回收算法 ;



2. 分代收集算法的核心思想是 :


不同的对象声明周期不同 , 承担的功能不同 ;

有些对象声明周期比较长如 Android 中的 Application , Activity 等组件 ;

有的对象生命周期很短 , 如打印日志时创建打印内容字符串 , 打印完毕后 , 该字符串对象马上就没用了 ;

这里要将不同的生命周期长度的对象 , 分别使用不同的垃圾回收机制进行处理 , 这样可以提高垃圾收集的效率 ;


3. 分治思想 : 垃圾对象收集时 , 需要对整个内存空间进行扫描 , 这样消耗很大 , 这里我们将内存分区 , 将生命周期短的对象放在一块内存中 , 生命周期长的对象放在另一块内存中 , 这样针对不同的内存块 , 采取不同的垃圾回收策略 ; ( 分治思想 )



4. 内存块分块 : 将 Java 内存堆分为 年轻代 , 老年代 , 新创建的对象放在年轻代中 , 老对象转移到老年代中 ;



5. 年轻代内存分区 : 年轻代内存分为 Eden 和 Survivor 两个区域 , Survivor 区域又分为 From Space 和 To Space ;


复制算法分区 : 很明显 Eden 和 Survivor 是复制算法中的两个区域 , From Space 和 To Space 也是复制算法中的两个区域 ;



6. 年轻代内存策略 : 复制算法 ;


新对象存放 : 新创建的对象都放在年龄代内存中的 Eden 区域中 ;


第一次复制算法 : 当 Eden 区域放满时 , 将存活的区域放到 Survivor 区域中的 From Space ( To Space ) 区域中 ;


第二次复制算法 : 当 From Space ( To Space ) 区域中存放后 , 会将年龄不足晋升的对象复制到另一侧的 To Space ( From Space ) 区域中 ;


晋升机制 : 年轻代内存中 , 一旦对象经理的 GC 次数达到一定阈值 , 就会晋升到老年代内存中 ;



7. 老年代内存策略 : 标记整理算法 ; Android 中使用的是 CMS 垃圾收集器 ;






三、 查看 Java 虚拟机


查看 Java 虚拟机 : 在命令行中执行 java -version , 即可查看当前 java 虚拟机情况 ;


C:\Users\octop>java -version
java version "1.8.0_221"
Java(TM) SE Runtime Environment (build 1.8.0_221-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.221-b11, mixed mode)
C:\Users\octop>

image.png


上述虚拟机是 HotSpot 虚拟机






四、 获取 Android 应用可使用最大内存


OOM 就是应用的内存超过了堆的最大值 , 内存分配的单位是进程 , 每个进程都会有一定的内存限制 ,



1. 获取当前 Android 手机的最大使用用内存 :



① 代码获取 : 调用 ActivityManager 对象的 getMemoryClass 方法获得内存对象 ;


② 执行如下命令 :


adb shell getprop dalvik.vm.heapsize


命令执行结果 :


C:\Users\octop>adb shell getprop dalvik.vm.heapsize
512m
C:\Users\octop>


image.png



2. 获取其它值 :


# 获取 app 最大申请内存, 超过就 OOM 
$ adb shell getprop dalvik.vm.heapsize
512m
# 获取初始内存大小
$ adb shell getprop dalvik.vm.heapstartsize
8m
# 正常情况下的内存值
$ adb shell getprop dalvik.vm.heapgrowthlimit
192m



3 . 指定极限大小 : 在 AndroidManifest.xml 中的 application 标签中指定 android:largeHeap 为 true , 为该进程设置堆内存极限大小 ;






五、 内存抖动标志


在 Android Profiler 中监控 Memory 内存 , 如果出现下图样式的内存图 , 说明出现了内存抖动 ;

image.png







六、 排查内存抖动


内存抖动查找 , 直接跳转到 Android Profiler 界面 , 点击 Dump Java Heap 按钮 , 保存一份内存快照 , 找出消耗内存最多的对象 , Allocations 个数最多的对象的类 , 该类对象大概率就是造成内存抖动的原因 ;

image.png







七、 常见的造成内存抖动操作


1. 日志打印 : 循环中使用 Log.i 函数打印日志 , 使用加号拼接字符串 , 尤其是每次拼接不同的字符串 , 每个字符串都需要创建释放 , 这样会造成内存抖动 ;



2. 循环操作 : 在循环内频繁创建对象 , 与销毁对象 ; 尽量将创建对象操作放在成员级别 , 或放在循环体外部 ;






八、 从内存优化角度选择集合


HashMap 集合 : HashMap 有一个默认大小 , 还有一个扩容因子 ; 如默认大小 100 , 扩容因子 0.8 , 该集合只能存储了 80 个 , 之后如果还想向其中存储数据 , 就需要扩容 , 扩容时 , 直接在默认大小基础上翻倍 ;



SparseArray 集合 : SparseArray 有默认大小 , 没有扩容因子 , 每次扩容 , 直接翻倍 ; SparseArray 的增删查改都要进行二分查找 ; SparseArray 的 Key 是 int 类型 , 其不必使用 Integer 包装类型 ; 数据量很大时 , 且需要键值对数据结构时 , 考虑使用 SparseArray 集合 ;


目录
相关文章
|
2月前
|
缓存 算法 Java
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
这篇文章详细介绍了Java虚拟机(JVM)中的垃圾回收机制,包括垃圾的定义、垃圾回收算法、堆内存的逻辑分区、对象的内存分配和回收过程,以及不同垃圾回收器的工作原理和参数设置。
70 4
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
|
23天前
|
算法
虚拟内存的页面置换算法有哪些?
【10月更文挑战第25天】不同的页面置换算法各有优缺点,在实际应用中,操作系统会根据不同的应用场景和系统需求选择合适的页面置换算法,或者对算法进行适当的改进和优化,以平衡系统的性能、开销和资源利用率等因素。
44 5
|
2月前
|
并行计算 算法 IDE
【灵码助力Cuda算法分析】分析共享内存的矩阵乘法优化
本文介绍了如何利用通义灵码在Visual Studio 2022中对基于CUDA的共享内存矩阵乘法优化代码进行深入分析。文章从整体程序结构入手,逐步深入到线程调度、矩阵分块、循环展开等关键细节,最后通过带入具体值的方式进一步解析复杂循环逻辑,展示了通义灵码在辅助理解和优化CUDA编程中的强大功能。
|
2月前
|
算法 JavaScript 前端开发
垃圾回收算法的原理
【10月更文挑战第13天】垃圾回收算法的原理
24 0
|
3月前
|
算法 程序员 Python
程序员必看!Python复杂度分析全攻略,让你的算法设计既快又省内存!
在编程领域,Python以简洁的语法和强大的库支持成为众多程序员的首选语言。然而,性能优化仍是挑战。本文将带你深入了解Python算法的复杂度分析,从时间与空间复杂度入手,分享四大最佳实践:选择合适算法、优化实现、利用Python特性减少空间消耗及定期评估调整,助你写出高效且节省内存的代码,轻松应对各种编程挑战。
45 1
|
2月前
|
存储 算法 C语言
MacOS环境-手写操作系统-17-内存管理算法实现
MacOS环境-手写操作系统-17-内存管理算法实现
37 0
|
4月前
|
存储 算法 Java
JVM自动内存管理之垃圾收集算法
文章概述了JVM内存管理和垃圾收集的基本概念,提供一个关于JVM内存管理和垃圾收集的基础理解框架。
JVM自动内存管理之垃圾收集算法
|
4月前
|
存储 算法 大数据
小米教你:2GB内存搞定20亿数据的高效算法
你好,我是小米。本文介绍如何在2GB内存中找出20亿个整数里出现次数最多的数。通过将数据用哈希函数分至16个小文件,每份独立计数后选出频次最高的数,最终比对得出结果。这种方法有效解决大数据下的内存限制问题,并可应用于更广泛的场景。欢迎关注我的公众号“软件求生”,获取更多技术分享!
180 12
|
4月前
|
算法 Java 应用服务中间件
探索JVM垃圾回收算法:选择适合你应用的最佳GC策略
探索JVM垃圾回收算法:选择适合你应用的最佳GC策略
|
4月前
|
存储 编译器 C语言
【C语言篇】数据在内存中的存储(超详细)
浮点数就采⽤下⾯的规则表⽰,即指数E的真实值加上127(或1023),再将有效数字M去掉整数部分的1。
389 0