详细介绍了Java对象的GC内存分配和回收策略以及常见GC日志参数。

文章目录

  • 1 GC日志的查看
    • 1.1 GC日志常用相关参数
    • 1.2 GC日志的输出和查看
  • 2 Java对象的GC内存分配和回收策略
    • 2.1 对象优先在Eden分配
      • 2.1.1 测试
        • 2.1.1.1 idea配置vm参数
      • 2.1.2 输出GC日志解释
    • 2.2 老年对象将进入老年代
      • 2.2.1 测试
      • 2.2.2 输出GC日志解释
      • 2.2.3 动态判定对象年龄
    • 2.3 大对象直接进入老年代
      • 2.3.1 案例
    • 2.4 TLAB上分配
    • 2.5 内存空间分配担保
    • 2.6 System.gc()

1 GC日志的查看

关于垃圾收集器,我们已经了解了很多,如果垃圾回收频繁出现,或者占用了太长的CPU时间, 就不得不引起重视。此时, 就需要一些跟踪参数来进一步甄别垃圾回收器的效率和效果,我们需要学会输出和产看GC日志,本文基于JDK1.8+IDEA,帮助大家输出和查看GC日志。

1.1 GC日志常用相关参数

参数 功能
-XX:+PrintGC 输出简单GC日志
-XX:+PrintGCDetails 输出详细GC日志,并且虚拟机退出前打印堆栈使用信息。
-XX:+PrintHeapAtGC 在每次GC前后都打印堆栈信息
-XX:+PrintGCTimeStamps 输出GC的时间戳(以基准时间的形式),JVM启动后的时间偏移量。
-XX:+PrintGCDateStamps 输出GC的时间戳(以日期的形式,如2020-04-02T10:09:01.045+0800)
-Xloggc:./gc.log 日志文件的输出路径
-XX:SurvivorRatio=8 定义了年轻代中Eden区与一个Survivor区的空间比例是8:1
-Xmx 设定程序运行期间最大可占用的内存大小
-Xms 设定程序启动时占用内存大小,大一点一般启动更快
-Xmn 设置年轻代占用内存大小
-XX:MaxTenuringThreshold=N 对象年龄达到N后,下一次GC将进入老年代,可以为0

1.2 GC日志的输出和查看

该部分内容将在Java对象的GC内存分配和回收策略章节中的案例中为大家介绍。

2 Java对象的GC内存分配和回收策略

2.1 对象优先在Eden分配

大多数情况下,对象在新生代Eden区中分配。

2.1.1 测试

public class GCLog {public static final int _1MB = 1024 * 1024;public static final int _1KB = 1024 ;public static void main(String[] args) {eden();}/*** vm参数:  -Xmx64M -Xms64M -Xmn10M -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -XX:+PrintGCDetails* 对象首先在Eden区分配*/public static void eden() {byte[] b1, b2, b3, b4, b5;b1 = new byte[1 * _1MB];b2 = new byte[1 * _1MB];b3 = new byte[1 * _1MB];b4 = new byte[1 * _1MB];b5 = new byte[1 * _1MB];}
}

2.1.1.1 idea配置vm参数

点击下拉箭头,点击Edit Configurations

点击+,点击Application

点击选择对应的Class,name 自己随意想改就改

配置VM参数,

-Xmx64M -Xms64M -Xmn10M -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -XX:+PrintGCDetails

点击Apply,完成。

2.1.2 输出GC日志解释

运行,查看输出:

HeapPSYoungGen      total 9216K, used 7516K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)eden space 8192K, 91% used [0x00000000ff600000,0x00000000ffd57060,0x00000000ffe00000)from space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)to   space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)ParOldGen       total 55296K, used 0K [0x00000000fc000000, 0x00000000ff600000, 0x00000000ff600000)object space 55296K, 0% used [0x00000000fc000000,0x00000000fc000000,0x00000000ff600000)Metaspace       used 3412K, capacity 4496K, committed 4864K, reserved 1056768Kclass space    used 374K, capacity 388K, committed 512K, reserved 1048576K

解读:

PSYoungGen中最前面的PS代表垃圾收集器是Parallel Scavenge收集器,回收的区域是新生代(YoungGen);

total 9216K, used 7516K中total表示新生代总共可使用内存,userd表示使用内存。

下面是新生代的三个分区:eden space、from space、to space 他们的大小默认是8:1:1。

ParOldGen中最前面的Par代表垃圾收集器是Parallel Old收集器,回收的区域是老年代(OldGen),包含object space(对象区域),占比100%。

Metaspace即JDK1.8的元空间,包含class space(类数据区域)。

eden space使用了91% used,而from space、to space,以及object space都使用了0%,说明案例中的对象是分配在eden区的。

2.2 老年对象将进入老年代

虚拟机给每个对象定义了一个对象年龄计数器。如果对象在Eden出生并经过第一次Minor GC后仍然存活,并且能够被Survivor容纳的话,将被移动到Survivor空间中,并将对象年龄设置为1。对象在Survivor区每熬过一次Minor GC,年龄就增加一岁,当它的年龄增加到一定程度(默认15岁)时,下一次GC就会被晋升到老年代中。对象晋升老年代的年龄最大值,可以通过参数 -XX:MaxTenuringThreshold=N来设置。

2.2.1 测试

public class GCLog {private static final int _1MB = 1024 * 1024;public static final int _1KB = 1024;public static void main(String[] args) {toOld();}/*** vm参数: * 对象首先在Eden区分配,年老对象进入老年代*/private static void toOld() {for (int i = 0; i < 15; i++) {byte[] b2 = new byte[_1MB];}}
}

2.2.2 输出GC日志解释

首先输入VM参数:

-Xmx20M -Xms20M -Xmn10M -XX:+PrintGCTimeStamps -XX:SurvivorRatio=4 -XX:+PrintGC -XX:MaxTenuringThreshold=1 -XX:+PrintHeapAtGC

表示在第二次GC时,1岁的对象将直接进入老年代。

输出如下:

{Heap before GC invocations=1 (full 0):PSYoungGen      total 8704K, used 6159K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)eden space 7168K, 85% used [0x00000000ff600000,0x00000000ffc03f88,0x00000000ffd00000)from space 1536K, 0% used [0x00000000ffe80000,0x00000000ffe80000,0x0000000100000000)to   space 1536K, 0% used [0x00000000ffd00000,0x00000000ffd00000,0x00000000ffe80000)ParOldGen       total 10240K, used 0K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)object space 10240K, 0% used [0x00000000fec00000,0x00000000fec00000,0x00000000ff600000)Metaspace       used 3465K, capacity 4496K, committed 4864K, reserved 1056768Kclass space    used 380K, capacity 388K, committed 512K, reserved 1048576K
0.101: [GC (Allocation Failure) [PSYoungGen: 6159K->888K(8704K)] 6159K->896K(18944K), 0.0010425 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Heap after GC invocations=1 (full 0):PSYoungGen      total 8704K, used 888K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)eden space 7168K, 0% used [0x00000000ff600000,0x00000000ff600000,0x00000000ffd00000)from space 1536K, 57% used [0x00000000ffd00000,0x00000000ffdde010,0x00000000ffe80000)to   space 1536K, 0% used [0x00000000ffe80000,0x00000000ffe80000,0x0000000100000000)ParOldGen       total 10240K, used 8K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)object space 10240K, 0% used [0x00000000fec00000,0x00000000fec02000,0x00000000ff600000)Metaspace       used 3465K, capacity 4496K, committed 4864K, reserved 1056768Kclass space    used 380K, capacity 388K, committed 512K, reserved 1048576K
}
{Heap before GC invocations=2 (full 0):PSYoungGen      total 8704K, used 7168K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)eden space 7168K, 87% used [0x00000000ff600000,0x00000000ffc22238,0x00000000ffd00000)from space 1536K, 57% used [0x00000000ffd00000,0x00000000ffdde010,0x00000000ffe80000)to   space 1536K, 0% used [0x00000000ffe80000,0x00000000ffe80000,0x0000000100000000)ParOldGen       total 10240K, used 8K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)object space 10240K, 0% used [0x00000000fec00000,0x00000000fec02000,0x00000000ff600000)Metaspace       used 3465K, capacity 4496K, committed 4864K, reserved 1056768Kclass space    used 380K, capacity 388K, committed 512K, reserved 1048576K
0.103: [GC (Allocation Failure) [PSYoungGen: 7168K->0K(8704K)] 7176K->732K(18944K), 0.0008609 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Heap after GC invocations=2 (full 0):PSYoungGen      total 8704K, used 0K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)eden space 7168K, 0% used [0x00000000ff600000,0x00000000ff600000,0x00000000ffd00000)from space 1536K, 0% used [0x00000000ffe80000,0x00000000ffe80000,0x0000000100000000)to   space 1536K, 0% used [0x00000000ffd00000,0x00000000ffd00000,0x00000000ffe80000)ParOldGen       total 10240K, used 732K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)object space 10240K, 7% used [0x00000000fec00000,0x00000000fecb7090,0x00000000ff600000)Metaspace       used 3465K, capacity 4496K, committed 4864K, reserved 1056768Kclass space    used 380K, capacity 388K, committed 512K, reserved 1048576K
}
HeapPSYoungGen      total 8704K, used 5322K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)eden space 7168K, 74% used [0x00000000ff600000,0x00000000ffb32b38,0x00000000ffd00000)from space 1536K, 0% used [0x00000000ffe80000,0x00000000ffe80000,0x0000000100000000)to   space 1536K, 0% used [0x00000000ffd00000,0x00000000ffd00000,0x00000000ffe80000)ParOldGen       total 10240K, used 732K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)object space 10240K, 7% used [0x00000000fec00000,0x00000000fecb7090,0x00000000ff600000)Metaspace       used 3471K, capacity 4496K, committed 4864K, reserved 1056768Kclass space    used 381K, capacity 388K, committed 512K, reserved 1048576K

上面的日志就是在每次GC前后打印堆内存信息。在最后再次打印堆内存信息。

GC信息解释:

  1. 0.101: [GC (Allocation Failure) [PSYoungGen: 6159K->888K(8704K)] 6159K->896K(18944K), 0.0010425 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
  2. 0.101:相对JVM启动时的时间
  3. GC:表明进行了一次垃圾回收,前面没有Full修饰,表明这是一次Minor GC。
  4. Allocation Failure:表明本次引起GC的原因是因为在年轻代中没有足够的空间能够存储新的数据了。
  5. PSYoungGen:表明本次GC发生在年轻代并且使用的是Parallel Scavenge收集器垃圾收集器。
  6. 6159K->888K(8704K):三个参数分别为:GC前该内存区域(这里是年轻代)使用容量,GC后该内存区域使用容量,该内存区域总容量。
  7. 6159K->896K(18944K):三个参数分别为:堆区垃圾回收前的使用大小,堆区垃圾回收后的使用大小,堆区总大小。
  8. 0.0010425 secs:该内存区域GC耗时,单位是秒
  9. [Times: user=0.00 sys=0.00, real=0.00 secs]:分别表示用户态耗时,内核态耗时和总耗时

看看其他信息:

Heap after GC invocations=1 (full 0)

表示第一次GC之后的信息,我们可以在下面看到from space 1536K, 57% used,表明第一次GC之后survivor区占用了大概一半多

Heap after GC invocations=2 (full 0)

表示第二次GC之后的信息,我们可以在下面看到ParOldGen total 10240K, used 732K,即有存活的对象转移到了老年代。

将-XX:MaxTenuringThreshold=1 的值改成2,输出如下

{Heap before GC invocations=1 (full 0):PSYoungGen      total 8704K, used 6159K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)eden space 7168K, 85% used [0x00000000ff600000,0x00000000ffc03f88,0x00000000ffd00000)from space 1536K, 0% used [0x00000000ffe80000,0x00000000ffe80000,0x0000000100000000)to   space 1536K, 0% used [0x00000000ffd00000,0x00000000ffd00000,0x00000000ffe80000)ParOldGen       total 10240K, used 0K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)object space 10240K, 0% used [0x00000000fec00000,0x00000000fec00000,0x00000000ff600000)Metaspace       used 3436K, capacity 4496K, committed 4864K, reserved 1056768Kclass space    used 376K, capacity 388K, committed 512K, reserved 1048576K
0.098: [GC (Allocation Failure) [PSYoungGen: 6159K->808K(8704K)] 6159K->816K(18944K), 0.0008813 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Heap after GC invocations=1 (full 0):PSYoungGen      total 8704K, used 808K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)eden space 7168K, 0% used [0x00000000ff600000,0x00000000ff600000,0x00000000ffd00000)from space 1536K, 52% used [0x00000000ffd00000,0x00000000ffdca020,0x00000000ffe80000)to   space 1536K, 0% used [0x00000000ffe80000,0x00000000ffe80000,0x0000000100000000)ParOldGen       total 10240K, used 8K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)object space 10240K, 0% used [0x00000000fec00000,0x00000000fec02000,0x00000000ff600000)Metaspace       used 3436K, capacity 4496K, committed 4864K, reserved 1056768Kclass space    used 376K, capacity 388K, committed 512K, reserved 1048576K
}
{Heap before GC invocations=2 (full 0):PSYoungGen      total 8704K, used 7162K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)eden space 7168K, 88% used [0x00000000ff600000,0x00000000ffc347e8,0x00000000ffd00000)from space 1536K, 52% used [0x00000000ffd00000,0x00000000ffdca020,0x00000000ffe80000)to   space 1536K, 0% used [0x00000000ffe80000,0x00000000ffe80000,0x0000000100000000)ParOldGen       total 10240K, used 8K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)object space 10240K, 0% used [0x00000000fec00000,0x00000000fec02000,0x00000000ff600000)Metaspace       used 3445K, capacity 4496K, committed 4864K, reserved 1056768Kclass space    used 377K, capacity 388K, committed 512K, reserved 1048576K
0.100: [GC (Allocation Failure) [PSYoungGen: 7162K->792K(8704K)] 7170K->808K(18944K), 0.0011583 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Heap after GC invocations=2 (full 0):PSYoungGen      total 8704K, used 792K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)eden space 7168K, 0% used [0x00000000ff600000,0x00000000ff600000,0x00000000ffd00000)from space 1536K, 51% used [0x00000000ffe80000,0x00000000fff46030,0x0000000100000000)to   space 1536K, 0% used [0x00000000ffd00000,0x00000000ffd00000,0x00000000ffe80000)ParOldGen       total 10240K, used 16K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)object space 10240K, 0% used [0x00000000fec00000,0x00000000fec04000,0x00000000ff600000)Metaspace       used 3445K, capacity 4496K, committed 4864K, reserved 1056768Kclass space    used 377K, capacity 388K, committed 512K, reserved 1048576K
}
HeapPSYoungGen      total 8704K, used 6306K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)eden space 7168K, 76% used [0x00000000ff600000,0x00000000ffb62900,0x00000000ffd00000)from space 1536K, 51% used [0x00000000ffe80000,0x00000000fff46030,0x0000000100000000)to   space 1536K, 0% used [0x00000000ffd00000,0x00000000ffd00000,0x00000000ffe80000)ParOldGen       total 10240K, used 16K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)object space 10240K, 0% used [0x00000000fec00000,0x00000000fec04000,0x00000000ff600000)Metaspace       used 3458K, capacity 4496K, committed 4864K, reserved 1056768Kclass space    used 379K, capacity 388K, committed 512K, reserved 1048576K

我们可以看到第2次GC之后object space 10240K, 0% used,说明1岁的对象并没有转移到老年代。

2.2.3 动态判定对象年龄

为了能更好地适应不同程序的内存状况,虚拟机并不总是要求对象的年龄必须达到MaxTenuringThreshold才能晋升老年代,如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无须等到MaxTenuringThreshold中要求的年龄。

2.3 大对象直接进入老年代

所谓的大对象是指,1、所需内存大于剩余内存的对象,2、所需连续内存空间大于剩余连续内存空间的对象,最典型的大对象就是那种很长的字符串以及数组(比如byte[]数组)。

由于eden和survivor区都无法容纳大对象,那么就会被尝试直接晋升到老年代。

虚拟机提供了一个-XX:PretenureSizeThreshold参数,令大于这个设置值的对象直接在老年代分配。此参数只对串行回收器以及ParNew回收有效, 而对ParallelGC回收器无效,默认值为0。

2.3.1 案例

public class GCLog {private static final int _1MB = 1024 * 1024;public static final int _1KB = 1024;public static void main(String[] args) {toOld();}/*** vm参数: -Xmx7M -Xms7M -Xmn2M -XX:+PrintGCDetails* 大对象直接进入老年代*/private static void toOld() {//byte[] bigB1 = new byte[2 * _1MB];//byte[] bigB2 = new byte[3 * _1MB];}
}

设置VM参数:

-Xmx7M -Xms7M -Xmn2M -XX:+PrintGCDetails

没有设置对象年龄,那么默认是15。运行三次,分别是不开放两个注释,开放第一个注释,开放第二个注释。结果如下:

第一次

[GC (Allocation Failure) [PSYoungGen: 1023K->504K(1536K)] 1023K->608K(7680K), 0.0009661 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
HeapPSYoungGen      total 1536K, used 1324K [0x00000000ffe00000, 0x0000000100000000, 0x0000000100000000)eden space 1024K, 80% used [0x00000000ffe00000,0x00000000ffecd210,0x00000000fff00000)from space 512K, 98% used [0x00000000fff00000,0x00000000fff7e010,0x00000000fff80000)to   space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)ParOldGen       total 6144K, used 104K [0x00000000ff800000, 0x00000000ffe00000, 0x00000000ffe00000)object space 6144K, 1% used [0x00000000ff800000,0x00000000ff81a040,0x00000000ffe00000)Metaspace       used 3431K, capacity 4496K, committed 4864K, reserved 1056768Kclass space    used 375K, capacity 388K, committed 512K, reserved 1048576K

第二次

[GC (Allocation Failure) [PSYoungGen: 1023K->504K(1536K)] 1023K->640K(7680K), 0.0011018 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
HeapPSYoungGen      total 1536K, used 1332K [0x00000000ffe00000, 0x0000000100000000, 0x0000000100000000)eden space 1024K, 80% used [0x00000000ffe00000,0x00000000ffecf2a8,0x00000000fff00000)from space 512K, 98% used [0x00000000fff00000,0x00000000fff7e010,0x00000000fff80000)to   space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)ParOldGen       total 6144K, used 2184K [0x00000000ff800000, 0x00000000ffe00000, 0x00000000ffe00000)object space 6144K, 35% used [0x00000000ff800000,0x00000000ffa22050,0x00000000ffe00000)Metaspace       used 3443K, capacity 4496K, committed 4864K, reserved 1056768Kclass space    used 377K, capacity 388K, committed 512K, reserved 1048576K

第三次

[GC (Allocation Failure) [PSYoungGen: 1023K->504K(1536K)] 1023K->616K(7680K), 0.0009587 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
HeapPSYoungGen      total 1536K, used 1375K [0x00000000ffe00000, 0x0000000100000000, 0x0000000100000000)eden space 1024K, 85% used [0x00000000ffe00000,0x00000000ffed9d70,0x00000000fff00000)from space 512K, 98% used [0x00000000fff00000,0x00000000fff7e010,0x00000000fff80000)to   space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)ParOldGen       total 6144K, used 3184K [0x00000000ff800000, 0x00000000ffe00000, 0x00000000ffe00000)object space 6144K, 51% used [0x00000000ff800000,0x00000000ffb1c050,0x00000000ffe00000)Metaspace       used 3471K, capacity 4496K, committed 4864K, reserved 1056768Kclass space    used 381K, capacity 388K, committed 512K, reserved 1048576K

从结果可以看到,由于2MB和3MB的对象大于新生代空间,因此,直接分配到了老年代,造成老年代内存被占用。实际上,如果老年代也无法分配,那么就会进行Full GC,最后抛出OOM异常。

2.4 TLAB上分配

对象主要分配在新生代的Eden区上,但是如果启动了本地线程分配缓冲,将按线程优先在专属TLAB(Thread Local Allocation Buffer,是线程私有的一块内存,如果设置了-XX:+UseTLAB,在线程初始化时,会申请一块指定大小的内存,只供当前线程使用,每个线程都有一个单独的Buffer,如果要分配内存,就在自己的Buffer上分配,不存在竞争的情况,能够提高分配的效率,但是当Buffer容量不够的时候,再重新从Eden区域申请一块继续使用)上分配。TLAB的空间是从Eden中划分出来的。

JDK1.8默认开启TLAB分配,可使用cmd命令 java -XX:+PrintFlagsFinal查看。

2.5 内存空间分配担保

在发生Minor GC之前,虚拟机会先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果这个条件成立,那么Minor GC可以确保是安全的。如果不成立,则虚拟机会查看HandlePromotionFailure设置值是否允许担保失败。如果允许,那么会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试着进行一次Minor GC,尽管这次Minor GC是有风险的;如果小于,或者HandlePromotionFailure设置不允许冒险,那这时也要改为进行一次Full GC。

前面提到过,新生代使用复制收集算法,但为了内存利用率,只使用了其中一个Survivor空间来作为轮换备份,因此当出现大量对象在Minor GC后仍然存活的情况下,就需要老年代进行分配担保,让Survivor无法容纳的对象直接进入老年代。但是前提老年代本身还有足够空间容纳这些对象。但是实际完成内存回收前是无法知道多少对象存活,所以只好取之前每一次回收晋升到老年代对象容量的平均值作为经验值,与老年代的剩余空间进行比较,决定是否进行Full GC来让老年代腾出更多的空间。

取平均值进行比较其实仍然是一种动态概率手段,也就是说如果某次Minor GC存活后的对象突增,远远高于平均值的话,依然会导致担保失败(HandlePronotion Failuer)。如果出现担保失败,那就只好在失败后重新发起一次Full GC。

JDK 6 Update 24之后的规则变为只要老年代的连续空间大于新生代对象总大小或者历次晋升的平均大小就会进行Minor GC,否则将进行Full GC。HandlePromotionFailure参数不会再影响到虚拟机的空间分配担保策略。

2.6 System.gc()

System.gc()会同时触发老年代和新生代进行回收。默认情况下, System.gc()即时生效,它会使用传统的Full GC的方式回收整个堆,即Serial+ Serial Old,并且会忽略参数中的UseG1GC和UseConcMarkSweepGC。

使用-XX:+ExplicitGCInvokesConcurrent后,System.gc()这种显示GC会使用并发发的方式进行回收。

而一般情况是我们认为,垃圾回收时自动进行的,无需手动触发。频繁的垃圾回收对系统性能造成较大影响。可以使用-XX:+DisableExplicitGC,则禁用显示GC,使得System.gc()等价于一个空函数。

对于默认并发回收器的JVM,例如JDK1.8使用System.gc()会在Full GC前触发一次Yong GC。这样做的目的是先将新生代进行一次收集,避免将所有回收工作同时交给一次Full GC进行,这样可以缩短一次停顿时间。-XX:-ScavengeBeforeFullGC 可以关闭这个特性,默认的情况下为true。

案例,vm 参数为 -XX:+PrintGC

public class GCLog {public static void main(String[] args) {sysGc();}private static void sysGc() {System.gc();}
}

输出结果可以看到JDK1.8调用gc方法,进行了两次GC。

[GC (System.gc())  5207K->848K(249344K), 0.0011507 secs]
[Full GC (System.gc())  848K->643K(249344K), 0.0044896 secs]

相关文章:

  1. 《深入理解Java虚拟机》

如有需要交流,或者文章有误,请直接留言。另外希望点赞、收藏、关注,我将不间断更新各种Java学习博客!

Java对象的GC内存分配和回收策略相关推荐

  1. JAVA之JVM之内存分配与回收策略(二)

    前言 对象的内存分配,往大的方向上讲,就是在堆上分配,少数情况下也可能会直接分配在老年代中,分配的规则并不是百分之百固定的,其细节决定于当前使用的是哪种垃圾收集器组合,当然还有虚拟机中与内存相关的参数 ...

  2. 深入理解Java虚拟机笔记之六内存分配与回收策略

    对象的内存分配,对象主要分配在新生代的Eden区上,如果启动了本地线程分配缓冲,将按线程优先在TLAB上分配.少数情况下也可能会直接分配在老年代中,分配的规则并不是百分百固定的,其细节取决于当前使用的 ...

  3. JVM:内存分配与回收策略?Full GC 的触发条件?StopTheWorld ?

    内存分配与回收策略 Minor GC 和 Full GC Minor GC:发生在新生代上,因为新生代对象存活时间很短,因此 Minor GC 会频繁执行,执行的速度一般也会比较快. Full GC: ...

  4. 深入理解Java虚拟机(第三弹)- JVM 内存分配与回收策略原理,从此告别 JVM 内存分配文盲

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:打卡活动第二期来啦,100% 能获得奖品个人原创+1博客:点击前往,查看更多 虚拟机系列文章 深入理解 Java ...

  5. Java 虚拟机内存分配与回收策略

    垃圾收集器与内存分配策略参考目录: 1.判断 Java 对象实例是否死亡 2. Java 中的四种引用 3.垃圾收集算法 4. Java9 中的 GC 调优 5.内存分配与回收策略 一.对象优先在 E ...

  6. 【拥抱大厂系列】百度面试官问过的 “JVM内存分配与回收策略原理”,我用这篇文章搞定了

    点个赞,看一看,好习惯!本文 GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了3个月总结的一线大厂Java面试总结,本人已拿腾 ...

  7. JVM之内存分配与回收策略

    JVM之内存分配与回收策略 来源 https://www.cnblogs.com/xiaoxi/p/6557473.html JVM分代垃圾回收策略的基础概念 来源 https://www.cnblo ...

  8. 实战:内存分配与回收策略

    实战:内存分配与回收策略 ​ Java技术体系的自动内存管理,最核心的目标就是自动化的解决两个问题:内存分配和内存回收,在之前我们讲的都是内存回收,现在我们来看一下内存分配的细节,这里我是使用JDK1 ...

  9. JVM3:实战:内存分配与回收策略

    实战:内存分配与回收策略 文章目录 实战:内存分配与回收策略 对象优先在Eden分配 大对象直接进入老年代 长期存活的对象将进入老年代 动态对象年龄判定 空间分配担保 对象优先在Eden分配 试分配三 ...

  10. JVM 之 内存分配与回收策略

    不诗意的女程序媛不是好厨师~ 转载请注明出处,From李诗雨-[https://blog.csdn.net/cjm2484836553/article/details/103842357] <J ...

最新文章

  1. Ubuntu 打开文件 (使用nautilus )
  2. 传智播客java基础的习题_传智播客java基础班(集合与IO)阶段测试题
  3. android rn 和webview,RN 组件webView 有可能出现的问题
  4. Windows版Qt
  5. 【springboot】【若依(ruoyi)】@RestController 接口跨域请求
  6. 趣味编程:C#中Specification模式的实现
  7. canvas1:简单介绍、开始使用、画直线+虚线
  8. java Map统计字符串中元素的数量
  9. MySQL管理利器 MySQL Utilities---mysqlreplicate
  10. DevEco Studio的下载
  11. Uniswap 24小时交易量12.5亿美元,占以太坊上Dex总量的50.05%
  12. 安卓下载功能中的广播接收器
  13. 使用Qt开发2D“沙盒”小游戏
  14. 刷脸支付将替代传统的聚合收款二维码
  15. The Basics of 3D Printing in 2015 - from someone with 16 WHOLE HOURS' experience
  16. [暑假]简单认识一下常用的字体 <<微软雅黑 黑体 和 宋体>>
  17. 【拼多多】拼多多顶级佣金助手(直连拼多多官方,无上级抽佣,各种免单)...
  18. Tableau制作全球电影数据分析/全球超市利润混合地图
  19. Type safety: The expression of type List needs unchecked conversion to conform to ListXXX解决办法
  20. PCB制板总结(AD制图)

热门文章

  1. excel 多行 取消隐藏_取消隐藏Excel行和列的问题
  2. Worker小Demo
  3. LGTM : code review 行话
  4. 给table表格加斜线
  5. 戴尔Latitude5285笔记本触摸板失灵的原因
  6. 网络没有运行wmi服务器,win7系统中没有wmi服务如何解决_win7没有wmi服务的解决方法...
  7. vs使用快捷键注销多行
  8. Colab 修改工作路径
  9. php字体颜色代码大全,CSS中关于文本字体颜色(CSS color)的详解
  10. 小恐龙游戏python_自动玩Chrome浏览器的小恐龙游戏