中国做外贸的网站有哪些,删除标题wordpress,网站建设服务公司案例,一般通过头发就能察觉到文章目录 垃圾回收算法垃圾回收算法的历史和分类垃圾回收算法的评价标准标记清除算法优缺点 复制算法优缺点 标记整理算法#xff08;标记压缩算法#xff09;优缺点 分代垃圾回收算法#xff08;常用#xff09;JVM参数设置使用Arthas查看内存分区垃圾回收执行流程分代GC算… 文章目录 垃圾回收算法垃圾回收算法的历史和分类垃圾回收算法的评价标准标记清除算法优缺点 复制算法优缺点 标记整理算法标记压缩算法优缺点 分代垃圾回收算法常用JVM参数设置使用Arthas查看内存分区垃圾回收执行流程分代GC算法内存为什么分年轻代、老年代 文章说明 垃圾回收算法
Java是如何实现垃圾回收的呢简单来说垃圾回收算法要做的有两件事
找到内存中存活的对象释放不再存活对象的内存使得程序能再次利用这部分空间 垃圾回收算法的历史和分类
1960年John McCarthy发布了第一个GC算法标记-清除算法。1963年Marvin L. Minsky 发布了复制算法。
本质上后续所有的垃圾回收算法都是在上述两种算法的基础上优化而来。 垃圾回收算法的评价标准
Java垃圾回收过程会通过单独的GC线程来完成但是不管使用哪一种GC算法都会有部分阶段需要停止所有的用户线程。这个过程被称之为Stop The World简称STW如果STW时间过长系统假死则会影响用户的使用。
如下图用户代码执行和垃圾回收执行让用户线程停止执行STW是交替执行的。 交替执行过程可以通过如下代码验证
package chapter04.gc;import lombok.SneakyThrows;import java.util.LinkedList;
import java.util.List;/*** STW测试*/
public class StopWorldTest {public static void main(String[] args) {new PrintThread().start();new ObjectThread().start();}
}/*** 打印线程*/
class PrintThread extends Thread{SneakyThrowsOverridepublic void run() {//记录开始时间long last System.currentTimeMillis();while(true){long now System.currentTimeMillis();// 如果不是垃圾回收影响这里每次都应该是输出100System.out.println(now - last);last now;Thread.sleep(100);}}
}/*** 创建对象线程*/
class ObjectThread extends Thread{SneakyThrowsOverridepublic void run() {Listbyte[] bytes new LinkedList();while(true){// 最多存放8g然后删除强引用垃圾回收时释放8gif(bytes.size() 80){// 清空集合强引用去除垃圾回收器就会去回收对象bytes.clear();}bytes.add(new byte[1024 * 1024 * 100]);Thread.sleep(10);}}
}代码运行之前设置如下JVM参数 所以判断GC算法是否优秀可以从三个方面来考虑
吞吐量
吞吐量指的是 CPU 用于执行用户代码的时间与 CPU 总执行时间的比值即吞吐量 执行用户代码时间 /执行用户代码时间 GC时间。吞吐量数值越高垃圾回收的效率就越高。 最大暂停时间
最大暂停时间指的是所有在垃圾回收过程中的STW时间最大值。比如如下的图中黄色部分的STW就是最大暂停时间显而易见上面的图比下面的图拥有更少的最大暂停时间。最大暂停时间越短用户使用系统时受到的影响就越短。 堆使用效率
不同垃圾回收算法对堆内存的使用方式是不同的。比如标记清除算法可以使用完整的堆内存。而复制算法会将堆内存一分为二每次只能使用一半内存。从堆使用效率上来说标记清除算法要优于复制算法。 上述三种评价标准堆使用效率、吞吐量以及最大暂停时间不可兼得。
一般来说堆内存越大回收对象就越多最大暂停时间就越长。想要减少最大暂停时间就要减少堆内存少量多次因为每次清理有一些准备工作因此垃圾回收总时间会上升吞吐量会降低。
没有一个垃圾回收算法能兼顾上述三点评价标准所以不同的垃圾回收算法它的侧重点是不同的适用于不同的应用场景即垃圾回收算法没有好与坏只有是否适合
秒杀场景购买只有很少的时间最大暂停时间越短越好有的场景程序就在后台处理数据暂停时间长一点无所谓目标是吞吐量高一点
标记清除算法
标记清除算法的核心思想分为两个阶段
标记阶段将所有存活的对象进行标记。Java中使用可达性分析算法从GC Root开始通过引用链遍历出所有存活对象。清除阶段从内存中删除没有被标记也就是非存活对象。
第一个阶段从GC Root对象开始扫描将对象A、B、C在引用链上的对象标记出来 第二个阶段将没有标记的对象清理掉所以对象D就被清理掉了。 优缺点
优点实现简单只需要在第一阶段给每个对象维护标志位在引用链上标记为1第二阶段删除标记值为0的对象即可。
缺点
碎片化问题由于内存是连续的所以在对象被删除之后内存中会出现很多细小的可用内存单元。如果我们需要的是一个比较大的空间很有可能这些内存单元的大小过小无法进行分配。如下图红色部分已经被清理掉了总共回收了9个字节但是每个都是一个小碎片无法为5个字节的对象分配空间。 分配速度慢。由于内存碎片的存在需要维护一个空闲链表极有可能发生每次需要遍历到链表的最后才能获得合适的内存空间。我们需要用一个链表来维护哪些空间可以分配对象很有可能需要遍历这个链表到最后才能发现这块空间足够我们去创建一个对象。如下图遍历到最后才发现有足够的空间分配3个字节的对象了。如果链表很长遍历也会花费较长的时间。 复制算法
复制算法的核心思想是
准备两块空间From空间和To空间每次在对象分配阶段只能使用其中一块空间From空间。
对象A首先分配在From空间 在垃圾回收GC阶段将From中的存活对象复制到To空间。
在垃圾回收阶段如果对象A存活就将其复制到To空间。然后将From空间直接清空。 将两块空间的From和To名字互换下次依然在From空间上创建对象。 完整的复制算法的例子
1、将堆内存分割成两块From空间 To空间对象分配阶段创建对象。 2、GC阶段开始将GC Root搬运到To空间 3、将GC Root关联的对象搬运到To空间 4、清理From空间并把名称互换 优缺点
优点
吞吐量高复制算法只需要遍历一次存活对象复制到To空间即可比标记-整理算法少了一次遍历的过程因而性能较好但是性能不如标记-清除算法因为标记清除算法不需要进行对象的移动不会发生碎片化复制算法在复制之后就会将对象按顺序放入To空间中所以对象以外的区域都是可用空间不存在碎片化内存空间。
缺点
内存使用效率低每次只能让一半的内存空间来给创建对象使用。
标记整理算法标记压缩算法
标记整理算法是对标记清理算法中容易产生内存碎片问题的一种解决方案。
核心思想分为两个阶段
标记阶段将所有存活的对象进行标记。Java中使用可达性分析算法从GC Root开始通过引用链遍历出所有存活对象。整理阶段将存活对象移动到堆的一端。清理掉存活对象的内存空间。 优缺点
优点
内存使用效率高整个堆内存都可以使用不像复制算法只能使用半个堆内存不会发生碎片化在整理阶段可以将对象往内存的一侧进行移动剩下的空间都是可以分配对象的有效空间
缺点
整理阶段的效率不高需要遍历多次对象还需要移动对象。整理算法有很多种比如Lisp2整理算法需要对整个堆中的对象搜索3次整体性能不佳。可以通过Two-Finger、表格算法、ImmixGC等高效的整理算法优化此阶段的性能。
分代垃圾回收算法常用
现代优秀的垃圾回收算法会将上述描述的垃圾回收算法组合进行使用其中应用最广的就是分代垃圾回收算法(Generational GC)。分代垃圾回收将整个内存区域划分为两块大区年轻代、老年代 Eden区对象刚被创建出来的时候放到的地方幸存者区-S0、幸存者区-S1用来实现复制算法
可以通过arthas来验证下内存划分的情况
在JDK8中添加-XX:UseSerialGC参数使用分代回收的垃圾回收器运行程序。在arthas中使用memory命令查看内存显示出三个区域的内存情况。 Eden survivor 这两块区域组成了年轻代。tenured_gen指的是晋升区域其实就是老年代。
JVM参数设置
可以设置的虚拟机参数如下
参数名参数含义示例-Xms设置堆的最小和初始大小必须是1024倍数且大于1MB比如初始大小6MB的写法 -Xms6291456 -Xms6144k -Xms6m-Xmx设置最大堆的大小必须是1024倍数且大于2MB比如最大堆80 MB的写法 -Xmx83886080 -Xmx81920k -Xmx80m-Xmn新生代的大小新生代256 MB的写法 -Xmn256m -Xmn262144k -Xmn268435456-XX:SurvivorRatio伊甸园区和幸存区的比例默认为8如新生代有1g内存则伊甸园区800MBS0和S1各100MB比例调整为4的写法-XX:SurvivorRatio4-XX:PrintGCDetailsverbose:gc打印GC日志无
老年代大小不需要设置因为新生代设置完之后老年代的大小就确定了总的堆内存-新生代内存
注如果使用其他版本的JDK或者使用其他回收器上面的部分参数可能就不会生效
使用Arthas查看内存分区
代码
package chapter04.gc;import java.io.IOException;
import java.util.ArrayList;
import java.util.List;/*** 垃圾回收器案例1*/
//-XX:UseSerialGC -Xms60m -Xmn20m -Xmx60m -XX:SurvivorRatio3 -XX:PrintGCDetails
public class GcDemo0 {public static void main(String[] args) throws IOException {ListObject list new ArrayList();int count 0;while (true){System.in.read();System.out.println(count);//每次添加1m的数据list.add(new byte[1024 * 1024 * 1]);}}
}使用arthas的memory展示出来的效果 heap展示的是可用堆。
垃圾回收执行流程
1、分代回收时创建出来的对象首先会被放入Eden伊甸园区。 2、随着对象在Eden区越来越多如果Eden区满新创建的对象已经无法放入就会触发年轻代的GC称为Minor GC或者Young GC。Minor GC会把需要eden中和From需要回收的对象回收把没有回收的对象放入To区算法使用的是复制算法。Minor GC结束之后****Eden区会被清空后面创建的对象又可以放到Eden区。 3、接下来S0会变成To区S1变成From区。当eden区满时再往里放入对象依然会发生Minor GC。 此时会回收eden区和S1(from)中的对象并把eden和from区中存活的对象放入S0。
注意每次Minor GC中都会为对象记录他的年龄初始值为0每次GC完加1。 4、如果Minor GC后对象的年龄达到阈值最大15默认值和垃圾回收器有关对象就会被晋升至老年代。 5、当老年代中空间不足无法放入新的对象时先尝试minor gc为啥**因为young满了之后部分对象年龄没有到15也被放在了老年区**minor gc可以清理young区来放新对象。如果空间还是不足就会触发Full GC停顿时间较长Full GC会对整个堆进行垃圾回收。如果Full GC依然无法回收掉老年代的对象那么当对象继续放入老年代时就会抛出Out Of Memory异常。 下图中的程序为什么会出现OutOfMemory 从上图可以看到Full GC无法回收掉老年代的对象那么当对象继续放入老年代时就会抛出Out Of Memory异常。
【测试代码】
//-XX:UseSerialGC -Xms60m -Xmn20m -Xmx60m -XX:SurvivorRatio3 -XX:PrintGCDetails
public class GcDemo0 {public static void main(String[] args) throws IOException {ListObject list new ArrayList();int count 0;while (true){System.in.read();System.out.println(count);//每次添加1m的数据list.add(new byte[1024 * 1024 * 1]);}}
}结果如下 老年代已经满了而且垃圾回收无法回收掉对象如果还想往里面放就发生了OutOfMemoryError。 分代GC算法内存为什么分年轻代、老年代
为什么分代GC算法要把堆分成年轻代和老年代首先我们要知道堆内存中对象的特性
系统中的大部分对象都是创建出来之后很快就不再使用可以被回收比如用户获取订单数据订单数据返回给用户之后就可以释放了。老年代中会存放长期存活的对象比如Spring的大部分bean对象在程序启动之后就不会被回收了。在虚拟机的默认设置中新生代大小要远小于老年代的大小。
分代GC算法将堆分成年轻代和老年代主要原因有
可以通过调整年轻代和老年代的比例来适应不同类型的应用程序提高内存的利用率和性能。新生代和老年代使用不同的垃圾回收算法新生代一般选择复制算法老年代可以选择标记-清除和标记-整理算法由程序员来选择灵活度较高。分代的设计中允许只回收新生代minor gc如果能满足对象分配的要求就不需要对整个堆进行回收(full gc)STW时间就会减少。尽可能做minor gc少做full gc尽量降低垃圾回收对程序运行的影响
文章说明
该文章是本人学习 黑马程序员 的学习笔记文章中大部分内容来源于 黑马程序员 的视频黑马程序员JVM虚拟机入门到实战全套视频教程java大厂面试必会的jvm一套搞定丰富的实战案例及最热面试题也有部分内容来自于自己的思考发布文章是想帮助其他学习的人更方便地整理自己的笔记或者直接通过文章学习相关知识如有侵权请联系删除最后对 黑马程序员 的优质课程表示感谢。