JVM深入学习(十四)-JVM中垃圾回收进阶概念

简介: 了解垃圾回收中的一些进阶概念,什么是内存泄漏和内存溢出,什么是STW

1. 内存溢出和内存泄漏问题


1.1 内存溢出

内存空间不足,且垃圾回收器也无法提供更多的内存,就会出现内存溢出情况

内存溢出多出现于堆空间,很少出现于虚拟机栈,但是栈也会出现Strack Overflow

正常情况下,各年龄代的垃圾回收正常回收对象已经足够,当内存空间实在不足时,触发一次FullGC,回收大量内存,保证程序正常,但是当内存占用的速度非常快的时候,超过垃圾回收的速度的时候就会出现OOM

1.1.1 内存空间不足

内存空间不足可以分为两种情况

  1. 堆内存初始化的内存较小 -Xms -Xmx分配 / 存在内存泄漏问题
  2. 代码中出现了大对象一直被引用的情况
  1. 例如方法区中的回收,当出现了大量动态类型生成的场合时,就可能导致永久代(jdk7)/元空间(jdk8) OOM

1.1.2 垃圾回收器无法提供更多的内存

当内存空间不足时,会先执行一次垃圾回收,清理空间

但是也并不是每次都会触发垃圾回收,特殊情况: 当要分配的对象大小超过了jvm堆内存的最大空间时,就会直接OOM,不再垃圾回收.

1.2 内存泄漏

内存泄漏的内存指的是jvm中的虚拟内存,并非物理内存.

1.2.1解释

  1. 对象已经不再使用,但是无法回收
  2. 对象的生命周期过长,导致无法回收

1.2.2后果

内存泄漏一旦发生,随着时间的推移,jvm可用内存会越来越少,最终可能导致jvm没有足够的内存从而程序崩溃的结果


2. STW(Stop The World)问题

stw指的是gc过程中,程序的所有线程全部暂停,等待gc完成的情况.

stw是不可避免的,在jvm垃圾回收的可达性算法中,我们必须要先分析所有可达对象,而jvm的GCRoots对象是在不停的变化中的,为了前后一致性,必须要停止其他所有线程,让GC线程进行操作.

STW是所有垃圾回收器都存在的事件,包括目前jvm使用G1以及未来的ZGC都无法避免,只能不断优化垃圾回收时间,减少停顿时间,提高用户体验.

开发中尽量少用System.gc() 这个是触发FullGC的,FullGC就会进行STW

3. 垃圾回收中的并行和并发

3.1 并行与并发的基本概念

并行: 同一个时间点,多个cpu同时处理

并发: 一个时间段内,一个/多个cpu同时处理

并行只存在于多个cpu或单个cpu多核心的情况下.

并行是不会抢占资源的,因为多核分别处理,不会互相干涉

并发是会抢占资源的,同一个处理器下同一个时间点只能执行一个线程.

3.2 垃圾回收中的并行和并发

垃圾回收也是通过线程来执行的,垃圾回收的线程也分为并行和并发

3.2.1 并行和串行

并行和串行针对的是垃圾回收线程之前可能是并行/串行

只有一个垃圾线程执行时,我们称之为串行

多个垃圾线程同时执行时,我们称之为并行

常用的垃圾回收线程有: ParNew/Parallel Scavenge/Parallel Old


3.2.2 并发

并发指的是垃圾回收线程和程序线程之间是并发的

垃圾回收线程和程序线程可能是并行的,也可能是并发的,但是不可能一直并行,因为存在不可避免的STW事件,最多交替执行

当垃圾回收线程和程序线程运行于不同的cpu上时,就是并行的,但这个过程并不能一直持续下去,当发生STW时,必然要停止程序线程,让垃圾回收线程运行.因此只能说在垃圾回收的一段时间内,垃圾回收线程和程序线程之间是并发的

4. 安全点和安全区域


4.1 安全点(SafePoint)

程序运行时,并不是在任意位置都可以停下来进行GC,只能在特定的位置才能停下来进行GC,这些特定的位置就是安全点

安全点的设置要恰到好处,太多会出现频繁gc,影响程序的性能,太少可能导致stw的时间过长甚至长时间无法gc会导致oom

安全点的设置位置也尽量选择执行时间较长的位置,比如方法调用,循环等位置,如果选择了执行时间较短的位置作为安全点,可能存在性能问题.

4.1.1 安全点的使用

当发生gc的时候,线程进入安全点的方式:

  1. 抢先式中断: 当gc发生时,就将所有线程都暂停,然后检查所有线程,是否有未到安全点的线程,如果有,恢复该线程,直到该线程到达安全点为止. (较为复杂,目前没有jvm再采用此种方式)
  2. 主动中断: 设置一个是否中断标志,每个线程运行到安全点的时候查询此标志,是否为true,为true则进行自己中断且挂起,当gc时,设置该中断标志即可.



4.2 安全区域(SafeRegion)

安全区域可以看作是安全点的扩充,将一块代码内,对象引用关系不会变化的区域称之为安全区域,在安全区域内,gc是不受影响的.

当线程发生时,如果某个程序线程处理seelp状态时,是无法相应gc线程,将线程的代码执行到具体的安全点再进行gc的,这个时候就需要安全区域来保证休眠线程不会影响到gc.

执行过程:

  1. 当线程进入到安全区域的时候,线程会进行标识,标识本线程已经进入安全区域了,这个时候如果发生gc,那么jvm就会忽略进入安全区域的线程(安全区域内对象关系不再变化)
  2. 当线程要离开安全区域的时候,需要检查gc是否完成,如果完成,那么就直接往下执行,如果没有完成,那么需要停止,等待gc完成后方可离开安全区域,这样是为了保证gc前后的一致性.
目录
相关文章
|
6月前
|
Arthas 存储 算法
深入理解JVM,包含字节码文件,内存结构,垃圾回收,类的声明周期,类加载器
JVM全称是Java Virtual Machine-Java虚拟机JVM作用:本质上是一个运行在计算机上的程序,职责是运行Java字节码文件,编译为机器码交由计算机运行类的生命周期概述:类的生命周期描述了一个类加载,使用,卸载的整个过类的生命周期阶段:类的声明周期主要分为五个阶段:加载->连接->初始化->使用->卸载,其中连接中分为三个小阶段验证->准备->解析类加载器的定义:JVM提供类加载器给Java程序去获取类和接口字节码数据类加载器的作用:类加载器接受字节码文件。
630 55
|
11月前
|
监控 算法 Java
Java虚拟机(JVM)垃圾回收机制深度剖析与优化策略####
本文作为一篇技术性文章,深入探讨了Java虚拟机(JVM)中垃圾回收的工作原理,详细分析了标记-清除、复制算法、标记-压缩及分代收集等主流垃圾回收算法的特点和适用场景。通过实际案例,展示了不同GC(Garbage Collector)算法在应用中的表现差异,并针对大型应用提出了一系列优化策略,包括选择合适的GC算法、调整堆内存大小、并行与并发GC调优等,旨在帮助开发者更好地理解和优化Java应用的性能。 ####
298 27
|
8月前
|
缓存 监控 算法
JVM简介—2.垃圾回收器和内存分配策略
本文介绍了Java垃圾回收机制的多个方面,包括垃圾回收概述、对象存活判断、引用类型介绍、垃圾收集算法、垃圾收集器设计、具体垃圾回收器详情、Stop The World现象、内存分配与回收策略、新生代配置演示、内存泄漏和溢出问题以及JDK提供的相关工具。
JVM简介—2.垃圾回收器和内存分配策略
|
6月前
|
缓存 算法 Java
JVM深入原理(八)(一):垃圾回收
弱引用-作用:JVM中使用WeakReference对象来实现软引用,一般在ThreadLocal中,当进行垃圾回收时,被弱引用对象引用的对象就直接被回收.软引用-作用:JVM中使用SoftReference对象来实现软引用,一般在缓存中使用,当程序内存不足时,被引用的对象就会被回收.强引用-作用:可达性算法描述的根对象引用普通对象的引用,指的就是强引用,只要有这层关系存在,被引用的对象就会不被垃圾回收。引用计数法-缺点:如果两个对象循环引用,而又没有其他的对象来引用它们,这样就造成垃圾堆积。
191 0
|
6月前
|
算法 Java 对象存储
JVM深入原理(八)(二):垃圾回收
Java垃圾回收过程会通过单独的GC线程来完成,但是不管使用哪一种GC算法,都会有部分阶段需要停止所有的用户线程。这个过程被称之为StopTheWorld简称STW,如果STW时间过长则会影响用户的使用。一般来说,堆内存越大,最大STW就越长,想减少最大STW,就会减少吞吐量,不同的GC算法适用于不同的场景。分代回收算法将整个堆中的区域划分为新生代和老年代。--超过新生代大小的大对象会直接晋升到老年代。
165 0
|
11月前
|
算法 网络协议 Java
【JVM】——GC垃圾回收机制(图解通俗易懂)
GC垃圾回收,标识出垃圾(计数机制、可达性分析)内存释放机制(标记清除、复制算法、标记整理、分代回收)
|
11月前
|
存储 监控 算法
Java虚拟机(JVM)垃圾回收机制深度解析与优化策略####
本文旨在深入探讨Java虚拟机(JVM)的垃圾回收机制,揭示其工作原理、常见算法及参数调优方法。通过剖析垃圾回收的生命周期、内存区域划分以及GC日志分析,为开发者提供一套实用的JVM垃圾回收优化指南,助力提升Java应用的性能与稳定性。 ####
|
1月前
|
存储 缓存 Java
我们来说一说 JVM 的内存模型
我是小假 期待与你的下一次相遇 ~
208 4
|
1月前
|
存储 缓存 算法
深入理解JVM《JVM内存区域详解 - 世界的基石》
Java代码从编译到执行需经javac编译为.class字节码,再由JVM加载运行。JVM内存分为线程私有(程序计数器、虚拟机栈、本地方法栈)和线程共享(堆、方法区)区域,其中堆是GC主战场,方法区在JDK 8+演变为使用本地内存的元空间,直接内存则用于提升NIO性能,但可能引发OOM。
|
7月前
|
Arthas 监控 Java
Arthas memory(查看 JVM 内存信息)
Arthas memory(查看 JVM 内存信息)
615 6