网站图片的作用,公司网站建设模块简介,英文营销网站,网站建设需要哪些常用技术上一章#xff1a;【JVM】JVM基础教程#xff08;三#xff09;-CSDN博客 目录
自动垃圾回收
方法区的回收
方法区回收条件
手动触发回收
堆回收
如何判断堆上的对象可以回收#xff1f;
可以给对象引用赋值null#xff0c;切断引用
引用计数法
循环引用缺点
查…上一章【JVM】JVM基础教程三-CSDN博客 目录
自动垃圾回收
方法区的回收
方法区回收条件
手动触发回收
堆回收
如何判断堆上的对象可以回收
可以给对象引用赋值null切断引用
引用计数法
循环引用缺点
查看垃圾回收日志
可达性分析法
MAT查看GC Root
五种对象引用
强引用
软引用
队列机制
使用场景-缓存
弱引用
虚引用和终结器引用
总结
垃圾回收算法
核心思想
垃圾回收算法的历史和分类
评价标准
标记清楚算法
复制算法
标记整理算法
分代垃圾回收算法
arthas查看分代之后的内存情况
调整内存区域的大小
垃圾回收器
为什么分代GC算法要把堆分成年轻代和老年代
垃圾回收器的组合关系 自动垃圾回收
C/C的内存管理
在C/C这类没有自动垃圾回收机制的语言中一个对象如果不再使用需要手动释放否则就会出现 内存泄漏。我们称这种释放对象的过程为垃圾回收而需要程序员编写代码进行回收的方式为手动回收。
内存泄漏指的是不再使用的对象在系统中未被回收内存泄漏的积累可能会导致内存溢出。 Java的内存管理
Java中的简化对象的释放引入了自动的垃圾回收Garbage Collection简称GC机制。通过垃 圾回收器来对不再使用的对象完成自动的回收垃圾回收器主要负责对堆上的内存进行回收。其他 很多现代语言比如C#、Python、Go都拥有自己的垃圾回收器所以也算不上Java的优势了在Java刚出的时候倒是个优势 垃圾回收的对比 自动垃圾回收的应用场景 方法区的回收 Java的内存管理
线程不共享的部分都是伴随着线程的创建而创建线程的销毁而销毁。而方法的栈帧在执行完方法之后就会自动弹出栈并释放掉对应的内存 继续说方法区的回收
方法区回收条件 方法区中能回收的内容主要就是不再使用的类 判定一个类是否可以被卸载需要同时满足下面三个条件 此类所有实例对象都已经被收回在堆中不存在任何类的实例对象以及子类对象加载该类的类加载器已经被回收该类对应的 java.lang.Class 对象没有在任何地方被引用 手动触发回收 如果需要手动触发垃圾回收可以调用System.gc()方法。语法System.gc()注意事项 调用System.gc()方法并不一定会立即回收垃圾仅仅是向Java虚拟机发送一个垃圾回收的请求具体是否需要 执行垃圾回收Java虚拟机会自行判断 开发中此类场景一般很少出现主要在如 OSGi、JSP 的热部署等应用场景中。 每个jsp文件对应一个唯一的类加载器当一个jsp文件修改了就直接卸载这个jsp类 加载器。重新创建类加载器重新加载jsp文件。 堆回收
如何判断堆上的对象可以回收
Java中的对象是否能被回收是根据对象是否被引用来决定的如果对象被引用了说明该对象还在使用不允许被回收。
比如下面代码的内存结构图 可以给对象引用赋值null切断引用 引用计数法
话说回来GC判断堆上的对象有没有被引用常用的两种方法引用计数法 和 可达性分析法
这里插一句Java只用可达性分析法 引用计数法会为每个对象维护一个引用计数器当对象被引用时加1取消引用时减1 循环引用缺点
引用计数法的优点是实现简单C中的智能指针就采用了引用计数法但是它也存在缺点主要有两点 1.每次引用和取消引用都需要维护计数器对系统性能会有一定的影响 2.存在循环引用问题所谓循环引用就是当A引用BB同时引用A时会出现对象无法回收的问题。 为什么会导致循环引用呢我查了一下资料
根据定义a引用了bb的引用计数1b引用了aa的引用计数1
正常情况下a b两个都赋值null就会将他俩的引用技术 -1这样就能回收了
不过由于a b互相引用所以即使赋值null他俩都不会 -1会维持1
所以我猜测应该是判断互相引用的优先级高与赋值null 查看垃圾回收日志 如果想要查看垃圾回收的信息可以使用-verbose:gc参数语法-verbose:gc java -verbose:gc -jar your-application.jar 可达性分析法
Java使用的是可达性分析算法来判断对象是否可以被回收。 可达性分析将对象分为两类 垃圾回收的根对象GC Root和普通对象 对象与对象之间存在引用关系 下图中A到B再到C和D形成了一个引用链可达性分析算法指的是如果从某个普通对象到GC Root对象是可达的对象就不可被回收 哪些对象被称之为GC Root对象呢
线程Thread对象引用线程栈帧中的方法参数局部变量等。系统类加载器也就是应用程序类加载器加载的java.lang.Class对象引用类中的静态变量监视器对象用来保存同步锁synchronized关键字持有的对象本地方法调用时使用的全局对象 MAT查看GC Root 下载eclipse Memory AnalyzerMAT工具Eclipse downloads - Select a mirror | The Eclipse Foundation 启动后会提示切换JDK版本17其实是JVM版本要求 切换版本 看我另一篇博客【Java】win10开发环境安装两个JDK【v8/17】_开发环境配置2种jdk版本-CSDN博客 就长这样
然后我们先用arthas生成堆内存快照 五种对象引用
几种常见的对象引用 强引用软引用弱引用虚引用终结器引用 强引用
可达性算法中描述的对象引用一般指的是强引用
即是GCRoot对象对普通对象有引用关系只要这层关系存在普通对象就不会被回收。
软引用
软引用相较于强引用是一种比较弱的引用关系如果一个对象只有软引用关联到它当程序内存不足时就会将软引用中的数据进行回收
在JDK1.2版之后提供了SoftReference类来实现软引用软引用常用于缓存中 软引用的执行过程如下 1.将对象使用软引用包装起来new SoftReference(对象)。 2.内存不足时虚拟机尝试进行垃圾回收。 3.如果垃圾回收仍不能解决内存不足的问题回收软引用中的对象。 4.如果依然内存不足抛出OutOfMemory异常。 队列机制
软引用中的对象如果在内存不足时回收SoftReference对象本身也需要被回收。 如何知道哪些SoftReference对 象需要回收呢 SoftReference提供了一套队列机制 1、软引用创建时通过构造器传入引用队列 2、在软引用中包含的对象被回收时该软引用对象会被放入引用队列 3、通过代码遍历引用队列将SoftReference的强引用删除 软引用也可以使用继承自SoftReference类的方式来实现StudentRef类就是一个软引用对象。
使用场景-缓存
软引用也可以使用继承自SoftReference类的方式来实现StudentRef类就是一个软引用对象。 通过构造器传入软引用包含的对象以及引用队列。 弱引用
弱引用的整体机制和软引用基本一致区别在于弱引用包含的对象在垃圾回收时不管内存够不够都会直接被回收。
在JDK1.2版之后提供了WeakReference类来实现弱引用弱引用主要在ThreadLocal中使用
弱引用对象本身也可以使用引用队列进行回收 虚引用和终结器引用 这两种引用在常规开发中是不会使用的。虚引用也叫幽灵引用/幻影引用不能通过虚引用对象获取到包含的对象。虚引用唯一的用途是当对象被垃圾回收器回收时可以接收到对应的通知。Java中使用PhantomReference实现了虚引用直接内存中为了及时知道直接内存不再使用从而回收内存使用了虚引用来实现终结器引用指的是在对象需要被回收时终结器引用会关联对象并放置在Finalizer类中的引用队列中在稍后由一条由FinalizerThread线程从队列中获取对象然后执行对象的finalize方法在对象第二次被回收时该 对象才真正的被回收。在这个过程中可以在finalize方法中再将自身对象使用强引用关联上但是不建议这样做。 总结 强引用Strong Reference —— 普通对象引用只有在没有任何强引用指向对象时垃圾回收器才会回收。 软引用Soft Reference —— 用于描述有用但非必需的对象内存不足时会被回收可用来实现缓存。 弱引用Weak Reference —— 用于描述非必需对象在下一次垃圾回收时无论内存是否充足都会被回收。 虚引用Phantom Reference —— 不决定对象的生命周期仅用于跟踪对象被垃圾回收的状态。 引用队列Reference Queue —— 与软引用、弱引用和虚引用配合使用用于检测对象何时被垃圾回收。 垃圾回收算法
核心思想
Java是如何实现垃圾回收的呢简单来说垃圾回收要做的有两件事 1、找到内存中存活的对象 2、释放不再存活对象的内存使得程序能再次利用这部分空间 垃圾回收算法的历史和分类
1960年John McCarthy发布了第一个GC算法标记-清除算法。
1963年Marvin L. Minsky 发布了复制算法。
本质上后续所有的垃圾回收算法都是在上述两种算法的基础上优化而来。 评价标准
垃圾回收算法的评价标准
STW
Java垃圾回收过程会通过单独的GC线程来完成但是不管使用哪一种GC算法都会有部分阶段需要停止所 有的用户线程。这个过程被称之为Stop The World简称STW如果STW时间过长则会影响用户的使用。 所以判断GC算法是否优秀可以从三个方面来考虑 吞吐量最大暂停时间堆使用效率 1.吞吐量
吞吐量指的是 CPU 用于执行用户代码的时间与 CPU 总执行时间的比值
即吞吐量 执行用户代码时间 / 执行用户代码时间 GC时间。
吞吐量数值越高垃圾回收的效率就越高 2.最大暂停时间
最大暂停时间指的是所有在垃圾回收过程中的STW时间最大值。
比如如下的图中黄色部分的STW就是最 大暂停时间显而易见上面的图比下面的图拥有更少的最大暂停时间。
最大暂停时间越短用户使用系统时 受到的影响就越短。 3.堆使用效率
不同垃圾回收算法对堆内存的使用方式是不同的。比如标记清除算法可以使用完整的堆内存。而复制算 法会将堆内存一分为二每次只能使用一半内存。从堆使用效率上来说标记清除算法要优于复制算法。
上述三种评价标准堆使用效率、吞吐量以及最大暂停时间不可兼得。
一般来说堆内存越大最大暂停时间就越长。想要减少最大暂停时间就会降低吞吐量。 堆内存越大最大暂停时间越长的原因 垃圾回收范围扩大 垃圾回收需要扫描整个堆堆越大垃圾回收器需要检查的对象数量越多回收所需时间越长。 对象存活率的影响 对象可能在堆中存在多个代际如年轻代、老年代等堆越大老年代的容量通常也会增大而老年代回收如Full GC通常是一次性回收整个区域导致停顿时间显著增加。 标记和清理的开销增加 垃圾回收的标记、清理和压缩操作对堆大小敏感堆越大这些操作的复杂度和执行时间都可能显著增加。 减少最大暂停时间会降低吞吐量的原因 更多的小型GC代价 为了减少最大暂停时间垃圾回收器通常采用增量回收或分区回收如G1 GC这些方法将一次性的大型回收分解为多次小型回收增加了垃圾回收的频率。 分而治之的开销 一些垃圾回收算法如并发标记-清理算法会在应用线程和回收线程之间并发运行这会占用部分CPU资源减少用于执行应用程序的时间从而降低吞吐量。 更频繁的Minor GC 减少最大暂停时间可能需要更小的年轻代Young Generation这会导致年轻代垃圾回收Minor GC更频繁地触发从而增加总体回收开销。 不同的垃圾回收算法适用于不同的场景。需要做出权衡 标记清楚算法
标记清除算法的核心思想分为两个阶段 1.标记阶段将所有存活的对象进行标记。Java中使用可达性分析算法从GC Root开始通过引用链遍历出 所有存活对象遍历一次 2.清除阶段从内存中删除没有被标记也就是非存活对象遍历一次 优缺点
优点实现简单只需要在第一阶段给每个对象维护标志位第二阶段删除对象即可。
缺点1.碎片化问题
由于内存是连续的所以在对象被删除之后内存中会出现很多细小的可用内存单元。如果我们需要的是一 个比较大的空间很有可能这些内存单元的大小过小无法进行分配。 缺点2.分配速度慢
由于内存碎片的存在需要维护一个空闲链表极有可能发生每次需要遍历到链表的最后才 能获得合适的内存空间 复制算法
复制算法的核心思想是 1.准备两块空间From空间和To空间每次在对象分配阶段只能使用其中一块空间From空间。 2.在垃圾回收GC阶段将From中存活对象复制到To空间。 3.将两块空间的From和To名字互换 完整的复制算法的例子 1.将堆内存分割成两块From空间To空间对象分配阶段创建对象。 2.GC阶段开始将GC Root搬运到To空间 3.将GC Root关联的对象搬运到To空间 4.清理From空间中未被标记的对象未被引用的对象还有弱引用并把名称互换 优缺点 标记整理算法
标记整理算法也叫标记压缩算法是对标记清理算法中容易产生内存碎片问题的一种解决方案。
核心思想分为两个阶段 1.标记阶段将所有存活的对象进行标记。Java中使用可达性分析算法从GC Root开始通过引用链遍历出 所有存活对象。 2.整理阶段将存活对象移动到堆的一端。清理掉存活对象之前占用的内存空间。 优缺点 分代垃圾回收算法
现代优秀的垃圾回收算法会将上述描述的垃圾回收算法组合进行使用其中应用最广的就是分代垃圾回收 算法(Generational GC)。
分代垃圾回收将整个内存区域划分为年轻代和老年代 arthas查看分代之后的内存情况
在JDK8中添加-XX:UseSerialGC参数使用分代回收的垃圾回收器运行程序
在arthas中使用memory命令查看内存显示出三个区域的内存情况 调整内存区域的大小 垃圾回收器
本章属于入门教程所以对于垃圾回收器的实战和原理会在进阶篇 为什么分代GC算法要把堆分成年轻代和老年代 系统中的大部分对象都是创建出来之后很快就不再使用可以被回收比如用户获取订单数据订单数据返回 给用户之后就可以释放了。老年代中会存放长期存活的对象比如Spring的大部分bean对象在程序启动之后就不会被回收了。在虚拟机的默认设置中新生代大小要远小于老年代的大小。 分代GC算法将堆分成年轻代和老年代主要原因有 1、可以通过调整年轻代和老年代的比例来适应不同类型的应用程序提高内存的利用率和性能。 2、新生代和老年代使用不同的垃圾回收算法新生代一般选择复制算法老年代可以选择标记-清除和标记-整理 算法由程序员来选择灵活度较高 3、分代的设计中允许只回收新生代minor gc如果能满足对象分配的要求就不需要对整个堆进行回收(full gc),STW时间就会减少 垃圾回收器的组合关系 笔记到此结束其余内容可以查看这个PDF
黑马JVM/基础/04-基础篇-垃圾回收.pdf · Autism_Btkrsr/Blog_md_to_pdf - 码云 - 开源中国 (gitee.com) 下一章