「性能优化系列」APP内存优化理论与实践

本文已参与创作者训练营第三期,概略查看:掘力计划|创作者训练营第三期正在进行,「写」出个人影响力

功用优化系列:

  • 建议优化
  • 内存优化
  • 布局优化
  • 卡顿优化
  • apk减肥优化
  • 电量优化

项目地址: fuusy/FuPerformjvm调优面试题ance

当一个运用一同工作变量英文越来越多的任务以及java工作培训班杂乱的事务,Android体系的内存管理机制现已无法满意内存的开释与收回,为了运用的稳定性与功用,去操控内存的创立和收回就成为了一个重要的出题java模拟器

本篇文章首要触及内容如下:

  • 政策的创立与收回;
  • 分配内存的办法,政策在JVM中的生命周期;
  • 判别政策是否需求被收回,废物收回算法;
  • 内存哆嗦、内存走漏的监控
  • Bitmap的巨细、重复监控计划;
  • 设备分级github敞开私库计划。

一、政策的创立和收回

1.1、政策的创立

在java中政策的创github下载建根柢上便是一个new,但new的不和在内存中做了些什么?并jvm调优面试题且政策对内存有哪些影响?又是怎样被收回的?……先了解这些根柢知识点对后边内存功用优化有很大的帮忙。

政策的创立根柢上有以下几点:

  1. 判别政策对应的类是否加载、链接和java工作培训班初始化;
    例如咱们运用new来创立一个User政策时,JVM虚拟机在收到new的jvm发动参数指令时,会去办法区查询该User类是否被引证,并查看User类是否现已被加载,链接和初始化过,假定没有,就需求先去实行类的加载进程。

  2. 为政策分配内存;
    Java堆中区别一块内存分配给政策,分配内存会依据Java堆是否规整,分为两种办法,指针磕碰和闲暇列表

    • 指针磕碰

      运用指针磕碰的条件是Java堆的内存归于规整模型,所谓指针磕碰,指的是运用一个指针将内存空间分为已被占用内存闲暇内存,当为一个政策进行内存分配java言语时,指针就变量英文向闲暇内存一侧移动,移动的间隔与政策巨细相等。如下图所示:

    「功能优化系列」APP内存优化理论与实践

    • 闲暇列监控怎样查看回放

      闲暇列表是在Java堆内存不完整的情jvm调优况下运用的办法,已运用内存与闲暇内存无规则,而且JVM别的保护了一张闲暇内存的java初学表,当有新政策需求分配内存时,就从闲暇列表中查找一块满意该政策的内存。

    「功能优化系列」APP内存优化理论与实践

  3. 处理并发安全问题;
    当政策jvm是什么意思创立很再三时,就需求去处理并发的问题,也便是线程GitHub安全。比方程序中多线程创立m和n两个政策,给m政策分配内存的一同也会给n政策分github官网配,假定这时分两个政策分配的是同一块内存,必定就呈现了冲突。
    为了处理这个并发的问题,JVM供应了两种办法。

    • CAJVMS算法+失利重试办法

      CAS是项达观锁技术,当多个线程检验一同更新一个变量时,只需其间一个线程可以更新变量的值,而其他的线程都是失利的,但失利的线程都不会被挂起,可以再次检验,直到成功为止。

    • 本地线程分配缓存区-TLAB

      所谓本地线程分配缓存区,便是当线程翻开时,就为每个线程在Eden区别配一块变量泵内存,然后当线程内部创立java模拟器政策时,就从自己java面试题的内存空间分配。若自己的内存缺乏或许竭尽时,就开始从堆内存中分配,这个时分便是选用CAS的办法。

  4. 初始化内存空间;
    将分配到的内存,除政策jvm是什么意思头以外都初始化为零值。这也是为什么政策的实例在Java代码中不赋初始值就可以直接运用的原因,访问的都是政策的零值。

  5. 设置政策的政策头;
    将政策的所属类,政策的HashCode以及政策的GC分代等数据存储到政策的政策头中。

  6. 实行init办法进行初始化
    实行init办法,初始化政策的成github是干什么的员变量,调用类的构造办法,到这儿,一个政策就被创立了。

1.2、政策在JVM中的生命周期

  1. 监控怎样装置建阶段,上面现已详细给出政策的创立进程;
  2. 运用阶段,当政策创立完结后,并分配给变量复制,状况切换到运用阶段;
  3. 不可见阶段,在程序中找不到政策的任何强引证;
  4. 不可达阶段,在程序中找不到政策的任何强引证,而且废物搜集器发现政策不可达;
  5. 搜集阶段,废物搜集器发现方变量泵针不可达,而且废物搜集器现已准备好对该政策的内存空间进行从头进行分配;
  6. 完结阶段,废物搜集器收回该政策的空间。

1.3、政策的收回

1.3.1、判别政策是否需求被收回

在对政策进行收回前,需求知道java难学吗该政策是否是废物。而判别监控摄像头一个政策是否需求被收回,有两种办法,引证计数法和java初学可达性剖析算法:

  1. 引证计数法
    所谓引证计数法,指的是政策会保护一个引证计数器,计监控app算被引证的次数,假定被引证一次,计数器就+监控他人微信聊天记录1,假定不在引证,则-1,知道计数器为0时监控装置流程,就说变量的界说明该政策可以被收回了。
    假定堆中有两个政策彼此引证,那他们的计数器都为1,就不会被收回,会构成内存走漏,这也是引证计数法的缺陷。

  2. 可达性剖析算法
    该算法根柢思路便是GC Roots作为起点jvm优化,从这个节点开始向下扫描,扫描到的政策即存活政策,未被扫描到的即需求被收回。
    GC Roots可以了解为由堆外指向堆内的引证, 一般来说,GC Roots包含(但不限于)以下几种:

    1. Java 办法栈桢中的局部变量;jvm参数
    2. 已加载类的静态变量;
    3. JNI handle监控器什么牌子最好清晰度高s;
    4. 已建议且未停止的 Java 线程。

了解了政策是否可回变量类型有哪些收,接下来就开始了解废物的收回算法。

1.3.java环境变量装备2、废物收回算法

  1. 符号铲除算法
    对存活的政策进行符号,在究竟扫描整个空间时,没有被符号的政策就会被收回。整个进程如监控体系下图所示:

    「功能优化系列」APP内存优化理论与实践

    该算法的缺陷从上图就可看到,铲除废物政策后,会发生不接连的内存碎片,当后边需求分配较大的政策时,会由于无法找到满意的接连内存空间,而触发废物收回,假定内存仍是缺乏,java模拟器则会异常。
    符号紧缩算法就处理了这个问题。

  2. 符号紧缩算法
    对存活的政策进行符号,在究竟扫描整个空间时,没有被符号的政策就会被收回,而且进行java环境变量装备内存碎片收拾。整个进程如下图所示:

    「功能优化系列」APP内存优化理论与实践

    虽然符号紧缩算法处理了符号铲除算法内存不规整的问题,但又存在新的问题。比方说,究竟对内存空间的收拾需求花费时刻,且指针也需求不断的从头移动,时刻耗费会随堆内存越来越大。

  3. 复制算法
    github中文社区贝算法是为了处理对碎片的废物收回,该算法一开始把堆一分为二,分为政策面和闲暇面,程序在政策面为政策分配空间,当方jvm调优面试题针面满了,就将每个存活政策复制到闲暇面,这样闲暇面变成了政策面,政策面变成了闲暇面。
    该算法的实行功率比符号收拾和符号铲除的功率都高jvm是什么意思,可是每次只能运用50%的内存空间。

  4. 分代废物收回算法
    分代废github官网物收回机制是依据不同政策的不同生命周期,选用不同的收回办法,进步收回功率。
    首要分为年青代和老时代。
    年青代: 用于存放github直播渠道永久回家新创立的政策,存活率较低的政策,经过屡次GC后,该政策依然存活,那么就监控摄像头会放入老时代。常用复制算法
    老时代: 用于存放存活时刻长的政策,常用符号铲除或符号收拾算法

    算法细节:

    • 政策新建,将存放在新生代的Eden区域,留神Suvivor区又分为两块区域,FromSuv和ToSuv;
    • 当年青代Eden满时,将会触发Minor GC,假定政策依然存活,政策将会被移动到Fromsuvivor空间,政策仍是在新生代;
    • 再次发生minor GC,政策还存活,那么将会选用复制算法,将java环境变量装备政策移动到ToSuv区域,此刻政策的年龄+1;
    • 再次发生minor GC,政策依然存活,此刻Survivor中跟政策Ob监控怎样查看回放ject同龄的政策还没有抵达Surivivor区的一半,所以仍是会继续选用复制算法,将fromSuv和ToSuv的区域进java言语行互换;
    • 当屡次发生jvm面试题monorGC后,政策实例依然存活,且此刻,此刻Survivor中跟政策Object同龄的政策抵达Surivivor区的一半,那么政策实例将会移动到老时代区域,或监控眼许政策经过屡次的收回,年龄抵达了15岁github直播渠道永久回家,那么也会搬家到老时代。

磨刀不误砍柴工,首要监控器什么牌子最好清晰度高根柢上了解了一些内存方面的知识点,那接下来就开始内存优化实践。

二、内存优化实践

内存优化首要分github敞开私库为几个大方向,Bitmap优化内存走漏内存哆嗦设备分级等。

2.1、内存哆嗦

内存哆嗦指的是内存再三分配和收回导致内存不稳java环境变量装备定,再三GC,会导致卡顿,甚至会OOM。至于为什么会构成卡顿变量与函数?是由于在GC时,会触发STW(stop the world)机制,也便是在实行废物搜集算法时,运用程序的其他全部线程都被挂起(除了废物搜集监控家用远程手机器之外),这个时分也就不会处理用户的操作变量类型有哪些事情,然后呈现卡顿。

下面将仿照一github中文官网网页个内存哆嗦状况,并运用Memory profile进行内存哆嗦的剖析。
这儿自界说了一个小球加载中的动画作用:

「功能优化系列」APP内存优化理论与实践

在开始小球动画后,咱们翻开翻开AS自带的Memory,从下图可以看到,内存的走势是在上下崎岖,而且内存也在监控家用远程手机不断的增加,这就代表着内存在不断的分配和收回,这变量泵便是内存哆嗦。

「功能优化系列」APP内存优化理论与实践

那内存哆嗦的详细问题呈现在哪里?

为了剖析内存哆嗦的问题所在,咱们先选取一段内存哆嗦的当地,可以看到在咱们选取的这段时刻里,AS的profile
都显现了每监控装置流程个政策的内存github打不开分配状况,如下所示。

「功能优化系列」APP内存优化理论与实践

从上面图片中的赤色框里就可以了解到,App发生内存哆嗦的原因首要便是app heap的前几项,而要匹配到项目中的代码就需求一个一个查看占用内存多的模块。

「功能优化系列」APP内存优化理论与实践
咱们先选择其间一个,在Allogithub下载cation Call Stack模块中清楚的看到详细所分配的仓库,一同也找到了构成堆中实例政策多的源代码。

「功能优化系列」APP内存优化理论与实践

github官网再创立政策实例的原代码在com.fuusy.fuperformancejvm面试题.memory.view.WaveView的136行。

「功能优化系列」APP内存优化理论与实践

哦~~ ,原来是自界说View时,在ojvm优化nDraw中再三创立Paint所致,处理的方监控怎样装置法便是将paint作为全局变量,在外部创立。

这个事例仅仅内存哆嗦中一个小小的缩影,当项目越来越大时,排查的作业难度也随之增加,这就要咱们在平常开发时,jvm内存模型就需求留神代码细节问题,尽可能在coding的进程中就减少内存问题。

内存哆嗦的留神事项:

  1. 防止在循环和再三调用的办法中创立政策github直播渠道永久回家
  2. 运用政策池,如Handler、Glide中的政策池。

2.2、内存走漏

内存走漏指的是程序中已分配的内存由于某种原因未开释或许无法开释,构成体系内存的浪Java费。

构成内存走漏的原因有许多,比方:

  • 长生命github敞开私库周期政策持有短生命周期政策的强引证,然后导致短生命周期政策无法被收回;
  • 异步线程持有短生命周期政策,如Handler、网络java工作培训班恳求或许其他作业线程持有短生命周期政策;
  • 资源未及时封闭,如Brojvm内存模型adcastReceiver、File、Cursor等;
  • 很多运用静态变量;
  • ……

当然,在实践项目中查找内存走漏的原因的办法也有许jvm发动参数多,比方干流东西LeakCanary、 MAT等。

2jvm优化.3、Bitmap优化

Bitmap作为程序中内存占用的大户,是必须优化的政策,之前写过一篇关于Bitmap优化的文章「功用优化系列」不运用第三方库,Bitmap的优化战略,可参jvm面试题看查看。

Bitmap除了根柢优化外,其实还需求在coding的进程中,就将Bitmap内存问题摧残在监控摇篮里,本篇文章就将java言语从图片巨细监控,重复图片监控两个方向变量进行论述。

2.3.1jvm调优、Bitmap巨细监控计划

Bitmap有一种从其标准上优化的方法,即当装载图片的容器例如ImageViewjvm内存模型只需100 * 100,而图片的分辨率为1800 * 800,这个时分将图片直接放置在容器上,很简略OOM,一同也是对图片和内存资源的一种糟蹋。当容器的宽高都很小于图片的宽高,其实就需求对图片进行标准上的紧缩.

而比较重要的点便是怎样判别Bijava言语tmap的标准符合图片容器?

想到的第一种办法便是可以自定java难学吗义一个ImageView,在View中去判别图片以及容器的巨细,假定图片太大,则进行标准上的紧缩或优化。这种办法简略有用,确实也处理了咱们的问题,但在实践开发中,除了代码侵入性强外,假定想要开发团队中的每个人加载ImageJavaView时都运用这个控件,也是一件很难翻开的事情。

为了愈加解耦性和减少代码侵入性,这儿介绍一种Bitmap巨细的监控计划-ARTHook

ARTHook浅显来讲便是一起增加代码批改原有逻辑。依据ARTHook的结构有许多,这儿介绍一个github永久回家地址常用结构-Epic。
Epic便是ART上的Dexposed(支撑 An变量是什么意思droid 5.0 ~ 11)。它可以拦截本进程内部简监控家用远程手机直任意的 Java 办法调用,可用于完结 AOP 编程github中文官网网页、工作时插桩、功用剖析等。

下面就依据Epic结构进行Bitmap巨细监控的编写。

增加依托

degithub下载pendencies {
implementation 'me.weishu:epi变量英文c:0.11.0'
}

新建一个Hook类用来编写图片巨细读取,比较,继承java工作培训班XC_MethodHook,并完结其a变量泵fterHookedMethod监控怎样装置jvm原理在其办法内完结需求监控的政策,详细监控的办法调用后将会调用该办法。

class BitmapARTHook : XC_MethodHook() {
@Throws(Throwable::class)
override fun afterHookedMethod(param: MethodHookParam) {
supgithub敞开私库er.afjava初学terHookedMethod(param)
val imageView = param.thisObject as I监控appmageView
chegithub官网ckBitmap(imageView, (param.thigithub打不开sObject as ImageView).drawab监控怎样查看回放le)
}
}

在afterHookedMethod办法里完结咱们需求的逻辑,这儿需求判别图片巨细并给出警示。那就加上图片巨细的监测办法。

if (bitmap.width >= width shl 1 && bitmap.height >= heightjvm内存模型 shl 1) {
warn(
bitmap.width,
bitmap.height,
width,
height,
RuntimeException监控怎样查看回放("Bitmap size too large")
)
}

详细代码监控家用远程手机请参看fuugithub永久回家地址sy/FuPerformance

写个测试来看看究竟的作用。在xml中新建一个ImageView,宽高都设置为100dp,在Activityjvm面试题中将一张分辨率为1300* 500的图片设置到ImageView中。

val imageView = findViewById&lt变量类型有哪些;ImageView>(R.id.iv_bitmap)
BitmapFactory.dejvm调优cod变量英文eRes监控怎样查看回放ource(resources, R.mipmap.bitmap1).apply {
imageView.setImageBitmap(this)
}

工作github下载后在终端可以看到图片巨细的提示信息。

「功能优化系列」APP内存优化理论与实践

「功能优化系列」APP内存优化理论与实践

2.3.2、重复图片监控

张邵文在高手课中提及重复图片指的是 Bitmapgithub敞开私库 的像素数据彻底一起,可是有多个不同的政策存在。给出的计划是运用HJavaAHA 库快速判别内存中是否存在重复的图片,而且将这些重复图片的 PNG、仓库等信息输出。

需求留神java环境变量装备的是需求运用8.0以下的机器,由于8.0今后Bitmap中的buffer现已放到native内存中。
中心代码与思路如下:

            //翻开hprof文件变量之间的联系
HprofBuffer buffer = new MemoryMappedFileBuffer(heapDumpFile);
HprofParser parser = new HprofParser(buffer);
//解析取得快照
co监控怎样装置m.squareup.haha.pe监控体系rflib.Snapshot snapshot = parser.parse();
snapshot.computeDominators();
//取得Bitmap Class
Collection<ClassObj> bitmapClasses = snapshot.findClasses("android.graphics.Bitmap");
//获取堆数据,这儿包含项监控怎样装置目app、体系、default heap的信息,github直播渠道永久回家需求进行过滤
Collection监控体系<Heap> heaps = snapshot.getHeaps();
long startTime = System.currentTimeMillis();
Tools.prigithub永久回家地址nt("---------------------- 开始 ----java面试题------------------- ");
fojava言语r (Heap heap : heaps) {
// 只需求剖析app和default heap即可
ijvm优化f (!heap.getName().equals("app") && !heap.getName().eq监控uals("default")) {
continue;
}
Tools.print("H变量泵eapName:" + heap.getName());
Majava工作培训班p<Integer, List<Ajava难学吗naly监控器什么牌子最好清晰度高ze变量泵rResult>> map = new HashMap<>()jvm原理;
for (ClassObj clazz : bitmapClass变量提升es) {
//从heap中取得全部的Bitmap实例
List<Instance> instances = clazz.getHeapInstance变量s(java工作培训班heap.getId());
for (变量类型有哪些int i = 0; i < instances.size(); i++) {
//从GcRojava难学吗ot开始遍历查找,Integer.MAX_VALUE代表无法被查找到,说明政策没被引证可以被收回
if (instances.get(i).getDistanceToGcRoot() == Integer.MAX_VALUE) {
continue;
}
List<AnalyzerResult> analyzerResujvm发动参数lts;
int curHashCode = Tools.getHashCodeByInstance(instances.get(监控i));
AnalyzerResult result = Tools.getAnalyzerResult(instances.get(i));
resultgithub怎样下载文件.setInstance(instjvm调优ances.get(i));
if (map.get(curHashCode) == null){
analyzerResults = new ArrayList&ltGitHub;>();
}else {
analyzerResults = map.get(curHashCode);
}
analyzerResults.add(result);
map.put(curHashCode, analyzerResults);
}
}
ifgithub敞开私库 (map.isEmpty()){
Tools.print("其时head暂无bitma变量之间的联系p政策");
}
for (Map.Entryjvm优化<Integer, List<AnalyzerResult>&jvm是什么意思gt; entr变量y : map.entrySet()){
List<AnalyzerResult> analyzerResults = entry.getValue();
//去除size小于2的,剩余的为重复图片。
if (analyzerResults.size() < 2){
continue;
}
}
}

详细计划可参看高手课Dem监控器什么牌子最好清晰度高o github.com/simplezhli/… 以及fuusy/FuPerformance

2.4、设备分级

所谓设备分级,指的是依据不同设备环境来考虑不同的内存优化战略。现在市场上手机github下载层出不穷,几乎每一监控变量的界说都会对手机功用进行进步,可是github直播渠道永久回家关于功用较差的手机,app运用的工作状况就会较差jvm发动参数

关于低端机用户可以封闭杂乱的动画,或许是某些功用;运监控app用 565 格局的图片,运用更小的缓存内java工作培训班存等。在实践环境下,不是每个用户的设备都跟咱们的测jvm面试题试机一样高端,在开发进程咱们要学会考虑功用要不要对低端机翻开、在体系资源吃紧的时分能变量与函数不能做降级。- 张邵文

那怎样进行设备分级?

Facebook其实开发了一个设备年份类库,它运用简略的算法将设备的 RAM、CPU 内核和时钟速度与这些特性被认为是高端监控眼的年份相匹配。使得咱们可以依据手机的硬件功用编写不同的逻辑。

RAM condition Year Class
768MB 1 core 2009
2+ cores 201github怎样下载文件0
1GB <1.3GHz 2011
1.3GHz+ 2012
1.5GB <1.8GHz 2012
1.8GHz+ 2013
2GB 2013
3GB 2014
5GB 2015
more 2016

而针对设备功用,咱们能做的优化就如上面张邵文所说。

  • 是否封闭动画;
  • 图片质量分级;
  • 为低功用设备设计简版运用。

设备分级实践

jvm参数加设备年份库的依托

implementatio变量的界说n 'com.faceb变量的界说ook.device.yearclass:yearclass:2.1.0'

获取设备年限以及进行设备分级。

val year = YearClass.get(applicationContext)
Log.d(java初学TAG, "Year: $yjava开发ear")
when {
year >= 2013 -> {
// Do adjava初学vgithub永久回家地址anced animation
}
year > 2010 -> {
// Do simple animation
}
else -> {
// Phone too slow监控app, don't do any animations
}
}

「功能优化系列」APP内存优化理论与实践

三、总结

内存优化是一个变量min表示什么类型的变量很大的出题,从内存在虚拟机中的创立与收回,到LeakCanary、MAT剖析东西的运用,再到内存走漏、内存哆嗦以及Bitmap的监控和优化,再分细一点,线上线下的监控计划、优化监控家用远程手机方法以及怎样一向坚持内存的稳定,这些github敞开私库都是内存优化需求注重的问题。

感谢阅览,这是一个功用优化系列,请继续注重。

项目地址: fuusy/FuPerformance

参看资料:

国内Top团队大牛带你玩转Ajvm面试题ndroid功用剖析与优变量提升
Android开发高手课

举荐阅览:

「功用优化系列」不运用第三方库,Bitmap的优化战略
「功用优化系列」APP发jvm调优起优化理论与实践(上)
「功用优化系列」APP建议优化理论与实践(下)

发表评论

提供最优质的资源集合

立即查看 了解详情