JVM GC 垃圾收集器

文章目录

  • System.gc()
  • 内存溢出(OOM)
    • OOM 的原因
  • 内存泄漏
  • 垃圾回收的并行与并发
    • 安全点与安全区域
  • Java 中的引用分类
    • 强引用(Strong Reference)
    • 软引用(Soft Reference)
    • 弱引用(Weak Reference)
    • 虚引用(Phantom Reference)
  • 垃圾回收器分类
    • 按线程数分
    • 按工作模式分
    • 按是否压缩内存来分
    • 按工作区间分
  • 垃圾回收器的性能指标
  • 垃圾收集器
  • JDK 8 的默认垃圾收集器
    • 查看 JDK 的默认垃圾收集器
  • Serial 收集器
  • ParNew 收集器
  • Parallel 收集器
  • CMS(Concurrent Mark Sweep 并发标记清除收集器
    • CMS 四个过程
    • 参数设置
  • G1(Garbage-First)收集器
    • 参数设置
    • Region 详解
    • G1 垃圾回收过程
  • 如何选择垃圾收集器
  • GC 相关参数

System.gc()

默认情况下,调用 System.gc(),其实际是调用的 Runtime.getRuntime().gc()(其实一个 native 方法),会显式的触发 Full GC,同时对新生代和老年代进行回收。但其调用无法保证一定会进行 GC,JVM 会在适当的时候进行 GC。

调用 System.runFinalization(); 方法可以强制调用失去引用的对象的 finalize 方法

内存溢出(OOM)

OOM,表示即便是 JVM GC 之后也没有空闲的内存可以使用了,就会导致 OOM。OOM 在新生代、老年代都会发生。

OOM 的原因

  • 堆内存不够:堆内存设置过小,通过 -Xmx 和 -Xms 来调整堆大小
  • 代码中创建了大量的对象且对象占用空间比较大。这种情况就是我们后续要进行内存优化或分析的重点情况。
  • 元空间内存不够:元空间默认情况下是使用的本地内存,不受堆空间大小限制,但受限于服务器物理内存的限制,如果元空间出现OOM,则是物理可用内存不够了。

特殊的,当创建一个超大的对象时(比如占 200M 空间),但 JVM 设置的 堆空间(比如只有150M),那么堆空间是无法放下此对象的,直接报 OOM。

内存泄漏

严格来说,只有对象不会再被程序使用,但又无法通过 GC 释放,就是内存泄漏。但实际使用中,由于各种疏忽,导致某些对象的生命周期超长,长时间无法释放,最后导致这种对象越来越多,最后 OOM,目前也称之为内存泄漏。

  • 单例:单例的生命周期一般是和应用程序一直,生命周期很长,在单例中如果引用了外部的对象,就能导致这个对象的生命周期延长,导致内存泄漏的情况
  • 带 close 方法的对象,如果 io、socket、连接池等,要及时调用 close 方法释放资源,否则也会导致内存泄漏的问题。

垃圾回收的并行与并发

  • 并行:只有多核CPU才有,多个线程分别在不同的CPU中并行执行。
  • 并发:多个线程在同一个CPU中执行,在某个时间段内,这些线程在CPU中不停的切换执行,此过程是非常的快的,看起来像是这些线程在同时执行。(实际单位时间内只有一个线程在执行)

安全点与安全区域

  • 安全点:应用程序并非在所有的时间点上都能直接停止下来执行 GC,只有在特点的程序执行位置才能开始 GC,这些位置称为“安全点”

一般选择一下执行时间较长的指令来设置安全点,比如:方法调用、循环跳转和异常跳转等。

  • 安全区域是指在代码片段中,对应的引用关系不会发生变化,在这个区域的任何一个位置开始 GC 都是安全的。因为安全点并不连续,如果在两个安全点中间需要 GC,也会导致无法开始 GC 的问题。

Java 中的引用分类

强引用(Strong Reference)

我们平时的代码中,几乎所有都是强引用。如:Object obj = new Object(); 。垃圾回收时,只要强引用关系存在,在 GC 时该对象不会被回收。

软引用(Soft Reference)

在系统将要发生内存溢出之前,将会把这些对象列如回收范围中,在第二次进行回收时(先回收不可达对象),不可达对象回收后内存任然不足时,进行回收。当第二次回收之后还没有足够的内存,才会抛出 OOM。

标记一个对象为软引用

Object obj = new Object();
Reference<Object> ref = new SoftReference<Object>(obj);

System.out.println(obj);
System.out.println(ref.get());

ref.clear();

// obj 是强引用,GC 的时候 Object 还是不会被回收,所以以上的写法要么不要定义 obj 引用,要么在后面将 obj = null,去掉强引用。
System.out.println(obj);
System.out.println(ref.get()); //  null

修改如下:

Object obj = new Object();
Reference<Object> ref = new SoftReference<Object>(obj);

obj = null;

System.out.println(obj);//  null
System.out.println(ref.get());//  not null

System.gc();

// 等待 gc 完成
Thread.sleep(10000);

// obj 是强引用,GC 的时候 Object 还是不会被回收,所以以上的写法要么不要定义 obj 引用,要么在后面将 obj = null,去掉强引用。
System.out.println(obj);//  null
System.out.println(ref.get()); //  not null 回收不可达对象之后,内存还不足时才会回收

Reference 是 java.lang.ref 包下的抽象类,其下有SoftReference、WeakReference、PhantomReference 等实现类

在这里插入图片描述

弱引用(Weak Reference)

当执行 GC 时,无论内存空间是否足够,都会回收掉被弱引用关联的对象。软引用和弱引用都非常适合用来保存那些可有可无的缓存数据。

Object obj = new Object();
Reference<Object> ref = new WeakReference<>(obj);

obj = null;

System.out.println(obj);//  null
System.out.println(ref.get());//  not null

System.gc();

// 等待 gc 完成
Thread.sleep(10000);

System.out.println(obj);//  null
System.out.println(ref.get()); //  null 发现即回收

虚引用(Phantom Reference)

无法通过虚引用来获得一个对象的实例,为一个对象设置虚引用关联的唯一目的是在这个对象被垃圾收集时收到一个系统通知。虚引用对对象的生命周期没有任何影响。

// 虚引用,必须传入 ReferenceQueue 引用队列
 Reference<Object> ref = new PhantomReference<>(new Object(),new ReferenceQueue<>());

 System.out.println(ref.get()); // null 虚引用无法通过 get 方法获取

 System.gc();

 System.out.println(ref.get()); //  null

引用强度:强引用 > 软引用 > 弱引用 > 虚引用

在这里插入图片描述

垃圾回收器分类

按线程数分

  • 串行垃圾收集器:在cpu、内存等硬件不怎么好的平台使用,串行回收器默认被应用在客户端的 Client 模式下的 JVM 中(32 位的JDK 是默认的 Client 模式,64 位的 JDK 默认为 Server 模式)
  • 并行垃圾收集器:在并发能力较强的平台下使用,并行回收器的停顿时间较串行回收器短。

按工作模式分

  • 并发式回收器:与应用线程交替执行,尽可能的降低停顿时间
  • 独占式回收器:停止所有用户线程,直到垃圾回收过程结束

按是否压缩内存来分

  • 压缩式回收器
    • 压缩后再分配内存空间使用指针碰撞的方式进行分配
  • 非压缩式回收器
    • 再分配内存空间使用空闲列表的方式进行分配

主要是以回收后,是否对内存碎片进行压缩整理(标记-压缩算法)

按工作区间分

  • 年轻代的垃圾回收器
  • 老年代的垃圾回收器

垃圾回收器的性能指标

  • 吞吐量:运行用户代码的时间所占总运行时间(程序的运行时间+垃圾回收时间)的比例。
  • 垃圾收集的开销:垃圾收集时间与总运行时间的比例。
  • 暂停时间:stop the World 的时间
  • 内存占用:堆区所占内存的大小
  • 收集频率和时间:相对来说频率越小且时间越小说明性能高。

当前垃圾收集器最注重的2点:吞吐量 + 暂停时间。在最大吞吐量的前提下,尽量的降低暂停时间。

垃圾收集器

常用的回收器:

  • 串行回收器:Serial、Serial Old
  • 并行回收器:ParNew、 Parallel Scavenge 、 Parallel Old
  • 并发回收器:CMS(Concurrent Mark Sweep 并发标记清除收集器)、G1(Garbage-First 垃圾优先收集器)

JDK 8 的垃圾收集文档中,(https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/),提及的两款垃圾收集器即为:CMS 和 G1

  • 新生代垃圾收集器:Serial、ParNew、 Parallel Scavenge
  • 老年代垃圾收集器:Serial Old、Parallel Old、CMS
  • 整堆垃圾收集器:G1

在这里插入图片描述

图片太大,可以使用新标签单独打开或者下载下来查看。

JDK 8 的默认垃圾收集器

查看 JDK 的默认垃圾收集器

  • 使用 -XX:+PrintCommandLineFlags 参数打印当前的应用程序中使用的垃圾收集器信息。示例信息如下:
-XX:InitialHeapSize=264885120 -XX:MaxHeapSize=4238161920 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC

我们最后会看到,-XX:+UseParallelGC ,说明 JDK 8 默认使用的垃圾收集器为:ParallelGC,其对应的老年代收集器为 ParallelOldGC

  • 使用 jinfo 命令查询
    在这里插入图片描述

图中 13392 这个线程id就是我们当前的执行程序。

Serial 收集器

Serial 收集器是一个串行的收集器,一般在可用内存较小(几十 M 到一两百 M ),且垃圾收集可以在较短的时间内完成的情况下。使用参数 -XX:UseSerialGC 指定老年代和新生代分别使用 SerialOldGC 和 SerialGC。(此处注意:没有 -XX:UseSerialOldGC的参数)。目前此收集器很少使用。

ParNew 收集器

ParNew 是并行回收器,其处理的是新生代的垃圾回收。其可以配合 CMS 和 Serial Old 来进行垃圾回收。使用参数 -XX:UseParNewGC 设置新生代使用 ParNew 收集器。使用 -XX:ParallelGCThreads 来限制线程的数量,默认数量为 CPU 的核数(建议不要超过 CPU 的核数)。目前此收集器也很少使用了。

Parallel 收集器

Parallel 收集器和 ParNew 收集器同样采用了复制算法、并行回收等机制,但 Parallel 有吞吐量优先的特性, Parallel 还有自适应调节策略。

参数配置

  • -XX:+UseParallelGC 指定年轻代使用 Parallel 收集器收集
  • -XX:+UseParallelOldGC 指定老年代使用 ParallelOld 收集器收集(此参数和 UserParallelGC 有一个开启,另一个自动开启)
  • -XX:+ParallelGCThreads 设置年轻代 Parallel 收集器的线程数。最好于 CPU 核数相等。
    • 默认情况下,如果 CPU 核数 < 8,ParallelGCThreads = CPU 核数,如果 CPU 核数 > 8,则 ParallelGCThreads = 3 + [(5 * CPU) / 8]
  • -XX:MaxGCPauseMillis 设置垃圾回收器最大的停顿时间(stop the World)。单位毫秒
    • 垃圾收集器会尽可能的把停顿时间控制在 MaxGCPauseMillis 以内,官网称此为软目标(尽可能的意思),建议谨慎设置此参数
  • -XX:+UseAdaptiveSizePolicy 启用自适应内存大小控制,默认为启用。在此模式下,年轻代的大小、eden 和 Survivor 的比例、晋升老年代的对象年龄等参数会被自动调整,以达到堆空间、吞吐量和停顿时间点一个平衡点。建议使用此参数即可。

CMS(Concurrent Mark Sweep 并发标记清除收集器

尽可能的降低 STW 的时间(低延迟),采用并发式标记清除算法进行垃圾收集,只负责老年的垃圾收集,且不能与 Parallel Scavenge 配合使用,只能和 Serial 或 ParNew 配合使用 。JDK 9 中已不推荐使用,被标记为 Deprecate。

CMS 四个过程

工作原理:初始标记、并发标记、重新标记、并发清理四个过程

  • 初始标记(Initial-Mark):在此阶段,程序中所有的工作线程都将会因为“Stop The World”机制出现短暂的暂停,此阶段主要标记处 GC Roots 能直接关联到的对象,由于关联的对象少,所以这里速度很快。标记完成后,之前被暂停的线程就会恢复。
  • 并发标记(Concurrent-Mark):从GC Roots 直接关联的对象开始遍历整个堆空间的对象,此过程耗时较长,但此过程是和用户线程并行的。
  • 重新标记(Remark):由于并发标记阶段是和用户线程并行的,所以在重新标记阶段要修正并发标记期间因用户线程执行而产生的变动,对这些变动的对象进行重新标记。这个时间通常比初始标记长,但远比并发标记短。
  • 并发清除(Concurrent-Sweep):此阶段删除掉标记为不可达的对象,释放内存空间。注意:此阶段不会移动可达对象,不会对内存进行压缩移动。

由于并发标记和并发清除阶段是和用户线程一起并行的,所以 CMS 收集器可以达到低延迟的一个标准。

也是由于用户线程和垃圾收集线程并行,如果确实没有对内存进行执行,此时 JVM 会启用 Serial Old 对老年代进行垃圾收集。

也是由于用户线程和垃圾收集线程并行,所以说不能使用标记压缩算法的(压缩时会改变对象的地址,改变对象的地址用户线程就无法执行了)

CMS 收集器是使用标记清除算法,会产生内存碎片,也只能使用空闲列表的方式进行再分配。

参数设置

  • -XX:+UseConcMarkSweepGC
    设置老年代使用 CMS 垃圾收集器。开启此参数后,将自动开启 -XX:UseParNewGC 。即新生代使用 ParNewGC ,老年代使用 CMS ,当发生 CMS 无法并行执行的时候启用 SerialOldGC
  • -XX:CMSInitiatingOccupancyFraction=percent
    设置初始化时触发老年代 CMS 垃圾回收的内存百分比。比如 80,表示内存使用率达到 80% 时,CMS 开始进行垃圾回收。默认为 -1。
    • 负数表示,CMS 使用 -XX:CMSTriggerRatio 来定义触发老年代 CMS 垃圾回收的阀值。
  • -XX:MinHeapFreeRatio=百分比
    设置GC事件后允许的最小可用堆空间百分比(0到100)。如果可用堆空间低于此值,则堆将被扩展。默认情况下,此值设置为40%。
  • -XX:CMSTriggerRatio:设置触发老年代 CMS 垃圾回收的内存百分比(占用 -XX:MinHeapFreeRatio 所设置的空间)。比如 80,表示内存使用率达到 80% 时,CMS 开始进行垃圾回收。默认为 80。

本文中提到了很多的参数,这些参数的设置官方文档就是 java 命令的文档 (https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html)

G1(Garbage-First)收集器

区域化分代式垃圾收集器,G1 是并行收集器,它把内存分割为很多不想关的区域(Region),每个Region可能是 Eden区,幸存者1区或幸存者0区,老年代等,这样可以避免在整堆中进行垃圾收集,将整个堆化整为零,一次回收其中一个或一些 Region,G1 进行垃圾回收时,会优先收集价值比较大的Region(可以认为当前不可达对象比较多的 Region 为价值比较大)。其在尽可能的保证低延迟的情况下提高吞吐量,其即可以回收新生代又可以回收老年代。

G1 在 JDK 7 加入,JDK 9 被设定为默认的垃圾回收器。

  • G1 在回收期间,可以有多个 GC 线程同时工作,可以有效利用多核计算能力,此时用户线程是挂起的。
  • G1 任然是分代收集的,只是 G1 中 Eden 区可能是多个 Region 组成,它们在内存中可能是不连续的。
  • G1 将内存划分为一个个的 Region,内存回收以 Region 为单位,Region 直接使用复制算法,但整体上可以看作标记压缩算法,所以 G1 可以有效避免内存碎片问题。Java 堆比较大的时候(大内存多处理器),G1 的优势会比较明显。
  • 由于 G1 不是整堆进行回收,它可以判断价值较大的 Region 进行垃圾回收的停顿时长,可以根据停顿时长进行有效的控制回收哪些 Region(原则上将,每次回收的 Region 较少,停顿时间就较少)。

参数设置

  • -XX:+UseG1GC
    启用 G1 垃圾收集器
  • -XX:G1HeapRegionSize=size
    设置每个 Region 的大小。范围是 1M ~ 32M,默认大小是根据堆的大小计算的,大概是堆大小的 1/2000。在 JVM 执行过程中每个 Region 的大小都是相同的且不会改变。
  • -XX:MaxGCPauseMillis=time
    设置期望的最大 GC 停顿时间。默认 200ms。(JVM 不一定能达到此设置)
  • -XX:ParallelGCThreads=threads
    设置年轻代和老年代并行回收线程数,默认为CPU的数量
  • -XX:ConcGCThreads=threads
    设置并发线程数。大概设置为 ParallelGCThreads 的 1/4 即可。
  • -XX:InitiatingHeapOccupancyPercent=percent
    设置堆占用率的百分比(0到100),在该百分比处启动并发GC循环。它由垃圾收集器使用,垃圾收集器根据整个堆的占用情况触发并发GC循环。
    • 默认情况下,初始值设置为45%。值为0表示不间断GC循环。

Region 详解

在这里插入图片描述

  • E 表示 Eden 区
  • S 表示幸存者区
  • O 老年代
  • H Humongous(翻译为巨大的):用于存储大对象,当一个对象大小大于 1.5 倍 Region 的时候,就会放入此区域。如果H区都无法存储,G1 会寻找连续的H区来存储,如果还找不到,可能导致 Full GC。G1 会将 H区当作老年代来对待。

官方图片如下,红色为 Eden 区,红色+S字母为幸存者区,H 为 Humongous。
在这里插入图片描述

G1 垃圾回收过程

在这里插入图片描述

  • 年轻代GC(Young GC):当年轻代内存不足时,触发 Young GC,G1 暂停所有应用程序线程,启动多个GC线程进行垃圾回收,对象移动过程和原来一样(Eden 区存活对象移动到幸存者区,达到年龄的对象移动到老年代等)
  • 老年代并发标记过程(Concurrent Marking):当内存达到阀值(默认45%)时,开始老年代并发标记过程
  • 混合回收(Mixed GC):标记完成马上开始混合回收过程,混合回收时,不需要收集整个老年代全部回收,可能只回收老年代的部分Region。
  • Full GC

垃圾收集的相关知识可参考 JDK 8 的官方文档 https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/

如何选择垃圾收集器

在通常情况下,我们可以直接提高堆内存大小来提高性能,但在无法提高堆内存大小的情况下,再来手动调整垃圾收集器

  • 如果应用程序的数据集较小(100 MB),则使用选项选择串行收集器-XX:+UseSerialGC .
  • 如果应用程序将在单处理器上运行,并且没有暂停时间要求,则使用选项选择串行采集器-XX:+UseSerialGC .
  • 如果应用程序性能是第一优先级,并且没有暂停时间要求,或者暂停1秒或更长时间是可以接受的,那么让VM选择收集器或选择并行收集器-XX:+UseParallelGC 。(吞吐量优先
  • 如果响应时间比总吞吐量更重要,并且垃圾收集暂停必须保持在大约1秒以下,则选择一个并发收集器 -XX:+UseG1GC (垃圾优先)或 -XX: 使用ConcMarkSweepGC(低延迟) 。

堆内存如果足够大(8G或以上,官网说明中是 10G),推荐使用 G1 收集器。

GC 相关参数

  • -XX:+PrintGC
    打印 GC 日志
2023-10-09T16:26:42.467+0800: [GC (Allocation Failure)  6743K->1008K(29696K), 0.0009465 secs]
2023-10-09T16:26:43.108+0800: [GC (Allocation Failure)  8390K->1144K(29696K), 0.0009188 secs]
2023-10-09T16:26:43.752+0800: [GC (Allocation Failure)  7585K->1184K(29696K), 0.0021388 secs]
2023-10-09T16:26:44.382+0800: [GC (Allocation Failure)  7469K->1232K(29696K), 0.0011422 secs]
2023-10-09T16:26:45.012+0800: [GC (Allocation Failure)  7524K->1248K(29696K), 0.0010169 secs]
2023-10-09T16:26:45.655+0800: [GC (Allocation Failure)  7544K->1264K(28672K), 0.0007992 secs]
2023-10-09T16:26:46.284+0800: [GC (Allocation Failure)  7543K->1259K(29184K), 0.0012118 secs]
2023-10-09T16:26:46.927+0800: [GC (Allocation Failure)  7540K->1259K(29184K), 0.0007576 secs]
2023-10-09T16:26:47.571+0800: [GC (Allocation Failure)  7541K->1259K(28160K), 0.0005698 secs]
2023-10-09T16:26:48.215+0800: [GC (Allocation Failure)  7542K->1259K(28672K), 0.0011637 secs]
2023-10-09T16:26:48.629+0800: [GC (Allocation Failure)  5474K->1259K(28672K), 0.0003956 secs]
2023-10-09T16:26:49.044+0800: [GC (Allocation Failure)  5474K->1259K(28672K), 0.0007266 secs]
2023-10-09T16:26:49.472+0800: [GC (Allocation Failure)  5474K->1259K(28672K), 0.0005000 secs]

说明(注:此时我们设置的堆内存大小为 30M):

  • 前面的时间是 -XX:+PrintGCDateStamps 参数的作用。
  • GC (Allocation Failure):表示 GC 发生的原因,Allocation Failure 表示内存分配失败
    6743K->1008K(29696K):表示 GC 之前内存占用 6743K,GC 之后内存占用 1008K(GC 之后空余内存 29696K)
    0.0009465 secs :表示 GC 时间
  • -XX:+PrintGCDetails
    打印详细 GC 日志
2023-10-09T16:40:37.840+0800: [GC (Allocation Failure) [PSYoungGen: 6743K->1018K(9216K)] 6743K->1026K(29696K), 0.0012821 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
2023-10-09T16:40:38.481+0800: [GC (Allocation Failure) [PSYoungGen: 8400K->1016K(9216K)] 8408K->1152K(29696K), 0.0009312 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
2023-10-09T16:40:39.119+0800: [GC (Allocation Failure) [PSYoungGen: 7457K->1016K(9216K)] 7593K->1184K(29696K), 0.0007436 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
2023-10-09T16:40:39.763+0800: [GC (Allocation Failure) [PSYoungGen: 7301K->1016K(9216K)] 7469K->1240K(29696K), 0.0009514 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
2023-10-09T16:40:40.406+0800: [GC (Allocation Failure) [PSYoungGen: 7308K->1016K(9216K)] 7532K->1256K(29696K), 0.0012255 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
2023-10-09T16:40:41.045+0800: [GC (Allocation Failure) [PSYoungGen: 7312K->1000K(8192K)] 7552K->1264K(28672K), 0.0010059 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
  • PSYoungGen 当前 GC 的类型,当前我们是默认的 Parallel 收集器,所以是 PSYoungGen,不同的收集器显示不一样。
  • [PSYoungGen: 6743K->1018K(9216K)]:中括号内,年轻代垃圾回收之前空间占用 6743K,回收后空间占用 1018K(回收后空闲 9216K)
  • 中括号外:6743K->1026K(29696K),年轻代 + 老年代的空间占用情况。
    [Times: user=0.00 sys=0.00, real=0.00 secs]:user表示用户态回收耗时,real 表示实际耗时,sys表示内核态回收耗时。
  • -XX:+PrintGCTimeStamps
    打印 GC 时间戳
  • -XX:+PrintGCDateStamps
    打印 GC 日期时间戳
  • -XX:+G1PrintHeapRegions
    打印 G1 收集器当前收集了哪些 Region
  • -XX:+PrintTenuringDistribution
    打印年龄信息
Desired survivor size 48286924 bytes, new threshold 10 (max 10)
- age 1: 28992024 bytes, 28992024 total
- age 2: 1366864 bytes, 30358888 total
- age 3: 1425912 bytes, 31784800 total
...

age 为 1 的对象是前一次 GC 幸存下来的对象,大小为 28992024 bytes,age 为 2 的对象是在前两次 GC 中幸存下来的对象,大小为 1366864 bytes,依此内推,每一行最后的 total 表示小于等于当前年龄的对象总大小。

示例中,28 992 024个字节在一次清除中幸存下来,并从eden复制到surviver空间,1 366 864个字节被年龄2的对象占用,等等。

  • -Xloggc:filename 输出详细的 GC 日志到文件
  • -XX:HeapDumpPath=path
    将 OutOfMemoryError 转储到 .hprof 文件,此设置虚配合 -XX:+HeapDumpOnOutOfMemoryError 一起使用

示例:-XX:HeapDumpPath=./java_pid%p.hprof , %p 表示进程id

  • -XX:+HeapDumpOnOutOfMemoryError
    当出现 java.lang.OutOfMemoryError 异常,则将根据 -XX:HeapDumpPath=path 配置输出 .hprof 文件

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/123325.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于SSM的小区物业管理系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

Flink SQL Regular Join 、Interval Join、Temporal Join、Lookup Join 详解

Flink ⽀持⾮常多的数据 Join ⽅式&#xff0c;主要包括以下三种&#xff1a; 动态表&#xff08;流&#xff09;与动态表&#xff08;流&#xff09;的 Join动态表&#xff08;流&#xff09;与外部维表&#xff08;⽐如 Redis&#xff09;的 Join动态表字段的列转⾏&#xf…

Linux 入门

Linux 入门 1&#xff1a;linux 用户 root 用户 &#xff1a;也叫超级用户&#xff0c;UID0&#xff0c;其权限最高。系统用户&#xff1a;也叫虚拟用户&#xff0c;UID 1-999普通用户: UID1000-60000, 可以登录系统,操作自己目录下的文件. 1.1:用户操作命令 切换用户: su …

STM32外部中断大问题

问题&#xff1a;一直进入中断&#xff0c;没有触发信号&#xff0c;也一直进入。 描述&#xff1a;开PA0为外部中断&#xff0c;刚刚很好&#xff0c;一个触发信号一个中断&#xff0c;中断函数没有丢&#xff0c;也没有抢跑&#xff0c;开PA1为外部中断也是&#xff0c;都很好…

nfs配置

1.NFS介绍 NFS就是Network File System的缩写&#xff0c;它最大的功能就是可以通过网络&#xff0c;让不同的机器、不同的操 作系统可以共享彼此的文件。 NFS服务器可以让PC将网络中的NFS服务器共享的目录挂载到本地端的文 件系统中&#xff0c;而在本地端的系统中来看&#…

C++初阶 | [二] 类和对象(上)

摘要&#xff1a;class&#xff0c;成员函数&#xff0c;成员变量&#xff0c;类的大小&#xff0c;this 指针 C语言是面向过程的&#xff0c;关注的是过程&#xff0c;分析出求解问题的步骤&#xff0c;通过函数调用逐步解决问题。 C是基于面向对象的&#xff0c;关注的是对象…

CSS 网页布局

网页布局有很多种方式&#xff0c;一般分为以下几个部分&#xff1a;头部区域、菜单导航区域、内容区域、底部区域&#xff1a; 1&#xff09;、头部区域位于整个网页的顶部&#xff0c;一般用于设置网页的标题或者网页的logo。 <style> body { margin: 0; } /* 头部样…

【Redis】list常用命令内部编码使用场景

文章目录 前置知识列表类型的特点 命令LPUSHLPUSHXRPUSHRPUSHXLRANGELPOPRPOPLINDEXLREMLINSERTLTRIMLSETLLEN 阻塞版本命令BLPOPBRPOP 命令总结内部编码测试内部编码 使用场景消息队列分频道的消息队列 模拟栈和队列 前置知识 列表类型是⽤来存储多个有序的字符串&#xff0c…

软件测试|Monkey基本参数介绍

说到android移动端稳定性测试&#xff0c;大家通常会想到android系统自动Monkey小猴子&#xff0c;通过Monkey命令模拟用户触摸点击屏幕、滑动、系统按键等操作来对设备上的app进行压力测试&#xff0c;来测试应用的稳定性和健壮性。 下面就说说monkey常用参数的用法~~ 1、-h…

Spring笔记(二)(黑马)(AOP面向切面编程)

01、AOP 简介 1.1 AOP的概念 AOP&#xff0c;Aspect Oriented Programming&#xff0c;面向切面编程&#xff0c;是对面向对象编程OOP的升华。OOP是纵向对一个事物的抽象&#xff0c;一个对象包括静态的属性信息&#xff0c;包括动态的方法信息等。而AOP是横向的对不同事物的…

spdk用户态块层详解

先通过回顾内核态的通用块层来详细介绍SPDK通用块层&#xff0c;包括通用块层的架构、核心数据结构、数据流方面的考量等。最后描述基于通用块层之上的两个特性&#xff1a;一是逻辑卷的支持&#xff0c;基于通用块设备的Blobstore和各种逻辑卷的特性&#xff0c;精简配置&…

C# OpenCvSharp 去除文字中的线条

效果 中间过程效果 项目 代码 using OpenCvSharp; using System; using System.Drawing; using System.Windows.Forms; using static System.Net.Mime.MediaTypeNames;namespace OpenCvSharp_Demo {public partial class frmMain : Form{public frmMain(){InitializeComponent…

Spring面试题:(四)Spring Bean生命周期

Bean生命周期的阶段 实例化初始化完成销毁 IoC容器实例化Bean的流程 Bean定义 Bean工厂处理 反射实例化Bean 初始化 完成存储到单例池 Bean生命周期 Bean初始化话过程 属性填充aware接口BeanPostProcessor前置处理InitialzingBean接口初始化方法自定义init方法BeanPost…

Oracle(15)Managing Users

目录 一、基础知识 1、Users and Security 用户和安全 2、Database Schema 3、Checklist for Creating Users创建用户步骤 二、基础操作 1、创建一个用户 2、OS Authentication 操作系统身份验证 3、Dropping a User 删除用户 4、Getting User Information 获取用户信…

搭建自己的MQTT服务器,实现设备上云(Ubuntu+EMQX)

一、EMQX介绍 这篇文章教大家在ECS云服务器上部署EMQX,搭建自己私有的MQTT服务器,配置EMQX实现设备上云,设备数据转发,存储;服务器我采用的华为云的ECS服务器,系统选择Ubuntu系统。 Windows版本的看这里: https://blog.csdn.net/xiaolong1126626497/article/details/1…

经验模态分解(Empirical Mode Decomposition,EMD)(附代码)

代码原理 EMD&#xff08;Empirical Mode Decomposition&#xff09;&#xff0c;也称为经验模态分解&#xff0c;是一种将非线性和非平稳信号分解成多个本征模态函数&#xff08;Intrinsic Mode Functions&#xff0c;简称IMF&#xff09;的方法。 EMD的基本原理是通过一系列…

掌动智能:UI自动化测试工具产品功能和优势

UI自动化测试工具是一种软件工具&#xff0c;用于模拟用户与应用程序的交互&#xff0c;检查应用程序的用户界面是否按预期工作。这些工具允许开发人员编写测试脚本&#xff0c;以模拟用户操作&#xff0c;例如点击按钮、输入文本、导航菜单等&#xff0c;然后验证应用程序的响…

哪款手机便签软件支持存储录音文件并支持转文字?

手机便签类软件带有存储录音转文字功能是比较实用的&#xff0c;很多人通常会整理很多录音类型的文件&#xff0c;录音文件整合在一起后&#xff0c;后续有需要可以逐条点开播放收听。尤其是在工作中&#xff0c;当领导说一些重点时&#xff0c;大家无法借助灵活的大脑来成功的…

如何判断被DDoS攻击

当网络和设备正常的情况下&#xff0c;服务器突然出现连接断开、访问卡顿、用户掉线等情况;服务器CPU或内存占用率出现明显增长;网络出入流量出现明显增长;网站或应用程序突然出现大量的未知访问;登录服务器失败或者登录过慢等等。以上是最为常见的服务器被 DDoS攻击后出现的几…

2.3 - 网络协议 - ICMP协议工作原理,报文格式,抓包实战

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;对网络安全感兴趣的小伙伴可以关注专栏《网络安全入门到精通》 ICMP协议 1、ICMP协议工作原理2、ICMP协议报文格式…