网站开发公司市场,网站的关键词报价的网站,搭建微信小程序需要服务器吗,高端h5网站开发一、GC概念
为了让程序员更专注于代码的实现#xff0c;而不用过多的考虑内存释放的问题#xff0c;所以#xff0c;在Java语言中#xff0c;有了自动的垃圾回收机制#xff0c;也就是我们熟悉的GC(Garbage Collection)。
有了垃圾回收机制后#xff0c;程序员只需要关…一、GC概念
为了让程序员更专注于代码的实现而不用过多的考虑内存释放的问题所以在Java语言中有了自动的垃圾回收机制也就是我们熟悉的GC(Garbage Collection)。
有了垃圾回收机制后程序员只需要关心内存的申请即可内存的释放由系统自动识别完成。
在进行垃圾回收时不同的对象引用类型GC会采用不同的回收时机
换句话说自动的垃圾回收的算法就会变得非常重要了如果因为算法的不合理导致内存资源一直没有释放同样也可能会导致内存溢出的。
当然除了Java语言C#、Python等语言也都有自动的垃圾回收机制。
二、垃圾判定算法 简单一句就是如果一个或多个对象没有任何的引用指向它了那么这个对象现 在就是垃圾如果定位了垃圾则有可能会被垃圾回收器回收。
如果要定位什么是垃圾有两种方式来确定
引用计数法可达性分析算法 引用计数法
一个对象被引用了一次在当前的对象头上递增一次引用次数如果这个对象的 引用次数为0代表这个对象可回收 当对象间出现了循环引用的话则引用计数法就会失效 目前上方的引用关系和计数都是没问题的但是如果代码继续往下执行如下 优点
实时性高无需等到内存不够的时候才开始回收运行时根据对象的计数器是否为 0就可以直接回收在垃圾回收过程中应用无需挂起。如果申请内存时内存不足则立刻报OOM错误区域性更新对象的计数器时只是影响到该对象不会扫描全部对象。
缺点
每次对象被引用时都需要去更新计数器有一点时间开销。浪费 CPU 资源即使内存任然够用仍然在运行时进行计数器统计。无法解决循环引用问题会引发内存泄露。 可达性分析算法
现在的虚拟机采用的都是通过可达性分析算法来确定哪些内容是垃圾。
会存在一个根节点【GC Roots】引出它下面指向的下一个节点再以下一个节点节点开始找出它下面的节点依次往下类推。直到所有的节点全部遍历完毕。 根对象是那些肯定不能当做垃圾回收的对象就可以当做根对象 局部变量静态方法静态变量类信息 核心是判断某对象是否与根对象有直接或间接的引用如果没有被引用则可以当做垃圾回收 X,Y 这两个节点是可回收的但是并不会马上的被回收 对象中存在一个方法【finalize】。当对象被标记为可回收后当发生GC时首先会判断这个对象是否执行了finalize方法如果这个方法还没有被执行的话那么就会先来执行这个方法接着在这个方法执行中可以设置当前这个对象与GC ROOTS产生关联那么这个方法执行完成之后GC会再次判断对象是否可达如果仍然不可达则会进行回收如果可达了则不会进行回收。
finalize方法 对于每一个对象来说只会执行一次。如果第一次执行这个方法的时候设置了当前对象与RC ROOTS关联那么这一次不会进行回收。 那么等到这个对象第二次被标记为可回收时那么该对象的finalize方法就不会再次执行了。
GC ROOTS
虚拟机栈栈帧中的本地变量表中引用的对象
/*** demo是栈帧中的本地变量当 demo null 时由于此时 demo 充当了 GC Root 的作用demo与原来指向的实例 new Demo() 断开了连接对象被回收。*/
public class Demo {public static void main(String[] args) {Demo demo new Demo();demo null;}
}方法区中类静态属性引用的对象
/*** 当栈帧中的本地变量 b null 时由于 b 原来指向的对象与 GC Root (变量 b) 断开了连接所以 b 原来指向的对象会被回收而由于我们给 a 赋值了变量的引用a在此时是类静态属性引用充当了 GC Root 的作用它指向的对象依然存活!*/
public class Demo {public static Demo a;public static void main(String[] args) {Demo b new Demo();b.a new Demo();b null;}
}方法区中常量引用的对象
/*** 常量 a 指向的对象并不会因为 demo 指向的对象被回收而回收*/
public class Demo {public static final Demo a new Demo();public static void main(String[] args) {Demo demo new Demo();demo null;}
}本地方法栈中 JNI即一般说的 Native 方法引用的对象
三、JVM 垃圾回收算法
1. 标记清除算法
标记清除算法是将垃圾回收分为2个阶段分别是标记和清除。
1根据可达性分析算法得出的垃圾进行标记
2对这些标记为可回收的内容进行垃圾回收 可以看到标记清除算法解决了引用计数算法中的循环引用的问题没有从root节点引用的对象都会被回收。
同样标记清除算法也是有缺点的
效率较低标记和清除两个动作都需要遍历所有的对象并且在GC时需要停止应用程序对于交互性要求比较高的应用而言这个体验是非常差的。重要通过标记清除算法清理出来的内存碎片化较为严重因为被回收的对象可能存在于内存的各个角落所以清理出来的内存是不连贯的。
2. 复制算法新生代
复制算法的核心就是将原有的内存空间一分为二每次只用其中的一块在垃圾回收时将正在使用的对象复制到另一个内存空间中然后将该内存空间清空交换两个内存的角色完成垃圾的回收。
如果内存中的垃圾对象较多需要复制的对象就较少这种情况下适合使用该方式并且效率比较高反之则不适合。 1将内存区域分成两部分每次操作其中一个。
2当进行垃圾回收时将正在使用的内存区域中的存活对象移动到未使用的内存区域。当移动完对这部分内存区域一次性清除。
3周而复始。
优点
在垃圾对象多的情况下效率较高清理后内存无碎片
缺点
分配的2块内存空间在同一个时刻只能使用一半内存使用率较低
3. 标记整理算法
标记整理压缩算法是在标记清除算法的基础之上做了优化改进的算法。和标记清除算法一样也是从根节点开始对对象的引用进行标记在清理阶段并不是简单的直接清理可回收对象而是将存活对象都向内存另一端移动然后清理边界以外的垃圾从而解决了碎片化的问题。 1标记垃圾。
2需要清除向右边走不需要清除的向左边走。
3清除边界以外的垃圾。
优缺点同标记清除算法解决了标记清除算法的碎片化的问题同时标记压缩算法多了一步对象移动内存位置的步骤其效率也有有一定的影响。
与复制算法对比复制算法标记完就复制但标记整理算法得等把所有存活对象都标记完毕再进行整理
四、分代收集算法
1. 概述
在java8时堆被分为了两份新生代和老年代【12】在java7时还存在一个永久代。 对于新生代内部又被分为了三个区域。Eden区伊甸园S0区幸存者区0S1区【811】
当对新生代产生GCMinorGC【young GC】
当对老年代代产生GCMajor GC
当对新生代和老年代产生FullGC 新生代 老年代完整垃圾回收暂停时间长应尽力避免
2. 工作机制 新创建的对象都会先分配到eden区 当伊甸园内存不足标记伊甸园与 from现阶段没有的存活对象 将存活对象采用复制算法复制到 to 中复制完毕后伊甸园和 from 内存都得到释放 经过一段时间后伊甸园的内存又出现不足标记eden区域to区存活的对象将存活的对象复制到from区 当幸存区对象熬过几次回收最多15次晋升到老年代幸存区内存不足或大对象会导致提前晋升
MinorGC、 Mixed GC 、 FullGC的区别是什么 MinorGC【young GC】发生在新生代的垃圾回收暂停时间短STW Mixed GC 新生代 老年代部分区域的垃圾回收G1 收集器特有 FullGC 新生代 老年代完整垃圾回收暂停时间长STW应尽力避免 名词解释 STWStop-The-World暂停所有应用程序线程等待垃圾回收的完成 五、JVM 垃圾回收器
在jvm中实现了多种垃圾收集器包括 串行垃圾收集器 并行垃圾收集器 CMS并发垃圾收集器 G1垃圾收集器
1. 串行垃圾回收器
Serial 和 Serial Old 串行垃圾收集器是指使用单线程进行垃圾回收堆内存较小适合个人电脑 Serial 作用于新生代采用复制算法 Serial Old 作用于老年代采用标记-整理算法
垃圾回收时只有一个线程在工作并且java应用中的所有线程都要暂停STW等待垃圾回收的完成。 2. 并行垃圾回收器
Parallel New 和 Parallel Old 是一个并行垃圾回收器JDK8默认使用此垃圾回收器 Parallel New 作用于新生代采用复制算法 Parallel Old 作用于老年代采用标记-整理算法
垃圾回收时多个线程在工作并且java应用中的所有线程都要暂停STW等待垃圾回收的完成。 3. CMS并发垃圾回收器
CMS全称 Concurrent Mark Sweep是一款并发的、使用标记-清除算法的垃圾回收器该回收器是针对老年代垃圾回收的是一款以获取最短回收停顿时间为目标的收集器停顿时间短用户体验就好。其最大特点是在进行垃圾回收时应用仍然能正常运行。 4. G1垃圾回收器 ⭐
① 概述 应用于新生代和老年代在JDK9之后默认使用G1 划分成多个区域每个区域都可以充当 edensurvivorold humongous其中 humongous 专为大对象准备 采用复制算法 响应时间与吞吐量兼顾 分成三个阶段新生代回收、并发标记、混合收集 如果并发失败即回收速度赶不上创建新对象速度会触发 Full GC ② Young Collection(年轻代垃圾回收) 初始时所有区域都处于空闲状态 创建了一些对象挑出一些空闲区域作为伊甸园区存储这些对象 当伊甸园需要垃圾回收时挑出一个空闲区域作为幸存区用复制算法复制存活对象需要暂停用户线程 随着时间流逝伊甸园的内存又有不足 将伊甸园以及之前幸存区中的存活对象采用复制算法复制到新的幸存区其中较老对象晋升至老年代
③ Young Collection Concurrent Mark (年轻代垃圾回收并发标记)
当老年代占用内存超过阈值(默认是45%)后触发并发标记这时无需暂停用户线程 并发标记之后会有重新标记阶段解决漏标问题此时需要暂停用户线程。 这些都完成后就知道了老年代有哪些存活对象随后进入混合收集阶段。此时不会对所有老年代区域进行回收而是根据暂停时间目标优先回收价值高存活对象少的区域这也是 Garbage First 名称的由来。
④ Mixed Collection (混合垃圾回收)
复制完成内存得到释放。进入下一轮的新生代回收、并发标记、混合收集 其中H叫做巨型对象如果对象非常大会开辟一块连续的空间存储巨型对象 六、强软弱虚引用 强引用
强引用只有所有 GC Roots 对象都不通过【强引用】引用该对象该对象才能被垃圾回收
User user new User();软引用
软引用仅有软引用引用该对象时在垃圾回收后内存仍不足时会再次触发垃圾回收
User user new User();
SoftReference softReference new SoftReference(user);弱引用
弱引用仅有弱引用引用该对象时在垃圾回收时无论内存是否充足都会回收弱引用对象
User user new User();
WeakReference weakReference new WeakReference(user);延伸话题ThreadLocal内存泄漏问题 ThreadLocal用的就是弱引用看以下源码
static class Entry extends WeakReferenceThreadLocal? {Object value;Entry(ThreadLocal? k, Object v) {super(k);value v; //强引用不会被回收}
}Entry 的 key 是当前 ThreadLocalvalue 值是我们要设置的数据。
WeakReference表示的是弱引用当JVM进行GC时一旦发现了只具有弱引用的对象不管当前内存空间是否足够都会回收它的内存。但是value是强引用它不会被回收掉。 ThreadLocal使用建议使用完毕后注意调用清理方法。 虚引用
虚引用必须配合引用队列使用被引用对象回收时会将虚引用入队由 Reference Handler 线程调用虚引用相关方法释放直接内存