记一次项目内存优化--内存泄漏(2),面试题精选

元空间(永久代)

永久代(持久代)是存放包含应用的类/方法信息,以及JRE库的类和方法信息。然而在Java8中,元空间取代了永久代,元空间(Metaspace)被称为“元数据区”。

需要注意的是:元空间并不在虚拟机中哦,而是使用本地内存(以前永久代是在jvm中的)。这样就解决了以前永久代的OOM问题,元数据和class对象存放在永久代中,容易出现性能问题和内存溢出,毕竟是和老年代共享堆空间。

堆内存分配策略

内存分配原则
  • 对象优先在Eden分配----如果说Eden内存空间不足,就会发生Minor GC /Young GC。
  • 大对象直接进入老年代----大对象:需要大量连续内存空间的Java对象,比如很长的字符串和大型数组。会导致新生代内存有空间,还是需要提前进行垃圾回收获取连续空间来放此大对象。Survivor区会进行大量的内存复制,-XX:PretenureSizeThreshold 参数 ,大于这个数量直接在老年代分配,缺省为0 ,表示绝不会直接分配在老年代。当Eden分配和Survivor区都没有足够空间存放此大对象时,则直接分配到老年代。
  • 长期存活的对象将进入老年代----Survivor区的对象达到一定年龄时,直接移到老年代。默认15岁,可以通过XX:MaxTenuringThreshold设置。
  • 动态对象年龄判定----为了能更好地适应不同程序的内存状况,虚拟机并不是永远地要求对象的年龄必须达到了MaxTenuringThreshold才能晋升老年代,如果在Survivor区中相同年龄所有对象大小的总和大于Survivor区的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无须等到MaxTenuringThreshold中要求的年龄。
  • 空间分配担保:新生代中有大量的对象存活,Survivor区不够,当出现大量对象在Minor GC后仍然存活的情况(最极端的情况就是内存回收后新生代中所有对象都存活),就需要老年代进行分配担保,把Survivor区无法容纳的对象直接进入老年代,只要老年代的连续空间大于新生代对象的总大小或者历次晋升的平均大小,就进行Minor GC,否则Full GC。
栈中分配对象
  • 逃逸分析----如果符合逃逸分析规则,则在栈中分配对象。
堆中的优化技术
  • TLAB ----Thread Local Allocation Buffer ,即线程本地线程分配缓冲。

栈区

当方法执行时,会在栈区内存中创建方法体内部的局部变量,方法结束后自动释放内存。

垃圾回收分代收集理论

我们都知道,在java中不同的对象存在不同的生命周期的,java对象在JVM中也存放在不同的区域,所以对不同生命周期不同的存放区,采取不同的回收策略,以提高效率。

当Eden区的内存空间不足时,系统触发Minor GC/Young GC, 随着GC持续进行,老年代的对象持续增加,导致老年代的内存空间不足,系统触发Major GC。当堆区或方法区内存空间不足时,系统触发Full GC。

Full GC:清理成本高,系统资源消耗高,对系统性能产生影响,很多性能什么都是针对Full GC进行的。 触发Full GC的条件有:

  • 调用System.gc()
  • 方法区空间不足
  • 堆区空间不足

不同阶段GC的特点

  • Minor GC/Young GC – 执行非常频繁,速度特别快。
  • Major GC – 速度上,一般会比Minor GC/Young GC慢十倍以上。
  • Full GC – Minor GC和Major GC都会执行,会发出"Stop the World"事件,会中断程序运行,直到GC完成。所以Full GC时,我们会感知到APP有卡顿之感。

垃圾回收分代收集对应的回收算法

  • 复制算法: 实现简单,运行高效,内存复制,内存利用率只有一半。
  • 标记-清除: 利用率100%,不需要内复制,有内存碎片
  • 标记-整理:利用率100%,没有内存碎片,需要内存复制(整理存活的对象,将其拷贝到一块连续内存中)

GC是如何判断对象存活

  • 可达性分析 (java) 通过一系列称之为“GC Roots”的对象作为起始点,从这些节点向下搜索,搜索所有的引用链,当一个对象到GC Roots有引用链,则说明这个对象存活着;当一个对象到GC Roots没有任何引用链(即GC Roots到对象不可达)时,则证明此对象是不可用的(所谓的垃圾)。
  • 引用计数算法(JVM早期使用的—已经不使用) A对象引用B 对象(+1),同时C对象引用B对象(1+1=2),计数法就是引用一次累加1次,如果没有引用就累减1次,如果归到0时,说明没有引用。缺点:就是相互引用。如A对象引用B对象,同时B对象引用A对象,很难去判断对象是否应该回收。

在Java, 可作为GC Roots的对象包括:

  • 方法区: 类静态属性的对象;
  • 方法区: 常量的对象;
  • 虚拟机栈(本地变量表)中的对象。
  • 本地方法栈JNI(Native方法)中的对象。

四种引用类型

  1. 强引用(StrongReference):JVM 宁可抛出 OOM ,也不会让 GC 回收具有强引用的对象。
  2. 软引用(SoftReference):只有在内存空间不足时,对象才会被回收。
  3. 弱引用(WeakReference):在 GC 时,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,对象都会被回收。
  4. 虚引用(PhantomReference):任何时候都可以被GC回收,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是否存在该对象的虚引用,来了解这个对象是否将要被回收。可以用来作为GC回收Object的标志。

我们定义对象,应该考虑使用那种引用,多考虑使用软引用(定义一些还有用但并非必须的对象)或弱引用(定义非必须对象)。

Android Studio的profiler工具

  1. 我们也可以利用Android Studio的profiler工具,方便快速查找、观察,简单分析一些对象生成情况。
  2. 也可以dump下hprof文件,结合MAT深入分析与排查,对象发生是否泄漏。
  3. 注意:MAT打开Android Studio的profiler里dump下hprof文件时,利用AS自带的hprof工具转换一下格式(通过命令hprof-conv -z 原hprof文件 输出hprof文件),不然打开是乱码。

当然检测内存泄漏的工具和方法有很多,就不一一列举了,感兴趣的可以网上查阅一下。

常见的内存问题场景

  • 静态成员/单例
  • 作为GC ROOT,持有短生命周期引用(如Activity)导致其短生命周期对象无法释放。
  • 集合类
  • 当使用集合时,只有添加元素,没有对应的删除元素。
  • 非静态内部类/匿名内部类
  • 如Handler postDelayed一个匿名Runnable,退出Activity时消息没处理完。
  • 上下文 – Context
  • 持有的上下文,需要特别注意。
  • 注册/反注册
  • 如EventBus只有注册没有注销。addXXXListener函数,需要有对应的removeXXXListener等等。
  • 未关闭/释放资源
  • 如FileOutputStream未close。
  • 系统Bug
  • WebView、InputMethodManager等

总结

  • 上面的内存相关知识也是自己学习的一种总结,有错误的可以留言指正。
  • 内存优化,需要对下面的知识有一定的了解。
  • Java内存分配模型
  • Java的四大引用及其使用场景
  • 内存检测工具及常用命令
  • GC Root的定义

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数HarmonyOS鸿蒙开发工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年HarmonyOS鸿蒙开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上HarmonyOS鸿蒙开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新

如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注鸿蒙获取)
img

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

VX:vip204888 (备注鸿蒙获取)**
[外链图片转存中…(img-3A6PUkd8-1712795565011)]

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 22
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值