jvm垃圾回收笔记

讲JVM垃圾回收,我们从以下7个部分来总结一下:

什么是垃圾回收,为什么要回收

垃圾怎么定义

定义垃圾的2种算法

垃圾收集的4种算法

垃圾收集器种类和选择

full gc时堆空间不足,一定会OOM吗

有了垃圾回收,java会不会内存泄露

1.什么是垃圾回收
        垃圾回收是为了防止java内存泄露,主要是防止堆内存的内存泄露。

------------------------------------------------分割线-------------------------------------------------------
2.什么是内存泄露
        内存泄露是jvm堆内存中死亡对象或没有引用的对象占据的内存空间没有释放,导致这部分空间造成浪费无法使用的现象。

------------------------------------------------分割线-------------------------------------------------------
3.理解四种对象引用
        java的引用分为4种引用:
1)强引用:比如 Test test = new Test();这里的test就是强引用,只要引用在,对象就不会被回收
2)软引用:如果内存比较紧张,可能会回收掉弱引用对象,这类对象不是必需对象
3)弱引用:非必需对象,只要触发gc,就会被回收,生命周期为2次gc之间
4)虚引用:再对象被回收时,收到一个系统通知,一般没啥用

------------------------------------------------分割线-------------------------------------------------------
4.怎么定义垃圾
        要定义对象是否是垃圾,就是要判断该对象有没有指针指向它,换句话说,如果一个对象没有引用指向它,那这个对象在堆中就可以被定义为垃圾。我们来写一个示例代码来看一下:
首先定义一个类A:

package com.test.main;

public class A {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

再来定义一个测试类:默认jvm

package com.test.main;

import java.util.ArrayList;
import java.util.List;

public class RubbishTest {

    public static void main(String[] args) {
        while(true){
            A instanceA = new A();
        }
        System.out.println("123");
    }
}

看代码中,在一个while死循环中,不停的去创建A的对象实例,你们猜会不会出现堆溢出?
答案是:不会。
原因:虽然while死循环,不停的在创建A对象,但是A对象创建完成之后,没有任何地方引用instanceA,所以instanceA创建完成之后会被回收,instanceA就被定义为垃圾对象。
注意:如果jvm设置堆内存很小的时候,不停的new 对象还是可能会造成堆溢出。

我们来运行该程序时的gc情况:
在这里插入图片描述
eden区一直没有增长,对象没有引用被回收,此时死循环中的对象实例全部属于"垃圾"。

------------------------------------------------分割线-------------------------------------------------------

定义垃圾的2种算法

1.引用计数法
        该算法在对象被创建存在引用的时候,在对象头空间中记录一个数值,代表当前对象引用数为1,当引用被释放,引用数会减少1,当引用数=0的时候,标记该对象为垃圾对象;
该算法已经被放弃,原因是因为:如果存在相互引用,那么对象被创建的时候,初始引用数为2,即使对象直接赋值为null,引用数依然不为0,无法被回收;

------------------------------------------------分割线-------------------------------------------------------

2.可达性分析算法
        提出一个概念,名为Gc Roots;
Gc Roots对象包括以下:
1)虚拟机栈中引用的对象
2)方法区中静态属性引用的对象
3)方法区中常量引用的对象
4)native方法引用的对象

从引用本身出发,往后查找,能够找到最终引用的对象,代表该对象可达,不进行垃圾回收;
如果不可达,则定义为垃圾

------------------------------------------------分割线-------------------------------------------------------

垃圾收集的4种算法

        我们上面已经说了2种怎么定义一个垃圾,现在垃圾被定义好了,如果从堆中进行gc收集呢?
1)标记清除法
该算法将定义为垃圾的对象进行标记,然后对这些打了标记的对象进行内存清理,会产生大量的不连续的内存碎片,就是一块儿内存有对象,一块儿内存没对象,互相紊乱交叉,不利用后续使用;

2)复制回收算法
该算法将内存一分为二,每次将需要收集的一块内存进行回收,剩余对象转移到另一块内存,那么当前这块儿内存就会被空闲出来,没有内存碎片;
缺点:代价有点大,每次只能使用一半的内存;

3)标记整理算法
该算法前面跟标记清除算法一样,先对垃圾进行标记,然后把标记过的垃圾进行移动,移动到同一侧进行回收,能够解决内存碎片问题,也能解决空间不利用的问题,但是内存地址移动整理过程,太过频繁,效率比较低;

4)分代收集算法
分代收集算法涉及到java内存模型,jvm将堆内存分为年轻代和老年代,同时年轻代分为2个survivor区,被称为from和to区,又称s0和s1区;这里可以参考我的jvm内存模型篇:jvm内存模型笔记
该算法,新生对象会进入eden区,进行垃圾收集时,会把剩余未清理的对象转移到s0区,再下一次,会把eden和from区同时转移到s1区,如此反复,来回在s0和s1进行复制交换,当s0和s1放不下,或者满足一定条件,比如gc分代年龄超过限制15次(默认值,可设置),就会将这些存活对象移到老年代,老年代再使用对应收集器进行收集;
这里有几个问题:
1:为什么需要survivor区?
答:起到缓冲作用,因为对象进行了一次survivor缓冲,在这个复制交换过程中,有可能对象会被回收掉,那么就减少了老年代gc的次数(如果从eden区直接到old区,老年代gc不是很频繁吗)

2:survivor为什么要分成2个?
答:其实默认是2个,也可以指定多个。为什么要2个,假设只有1个的话,从eden区到survivor区,survivor区如果有对象存活比较久,当垃圾对象被回收,存活对象还继续在survivor,那不是跟标记清除算法一样,又存在内存碎片了吗
------------------------------------------------分割线-------------------------------------------------------

垃圾收集器种类和选择

分代收集,代表了年轻代和老年代使用不同的收集算法,使用不同的收集器

收集器的种类:

1)Serial收集器:单线程收集器,采用单线程-复制回收算法,用于年轻代;
2)Serial Old收集器:单线程收集器,采用单线程-标记整理算法,用于老年代;
3)ParNew收集器:多线程版的Serial收集器,采用多线程-复制回收算法,用于年轻代;
4)Parallel Scavenge收集器:多线程收集器,采用多线程-复制回收算法,注重吞吐量,比如虚拟机运行了10分钟,有1分钟在进行垃圾收集,那么吞吐量就是99%,也叫吞吐量优先收集器,该收集器是-server模式下的虚拟机默认垃圾收集器,用于年轻代;
5)Parallel Old收集器:Parallel Scavenge的老年代版本,采用多线程-标记整理算法,用于老年代
6)CMS收集器:全称Conrrurent Mark Sweep,多线程收集器,采用多线程-标记清除算法,用于老年代;

年轻代和老年代搭配使用规则,如下图:
在这里插入图片描述

------------------------------------------------分割线-------------------------------------------------------

full gc没有可回收对象或者空间不足时必定会oom吗

答案:不一定
我们来一段代码,同时设置一下jvm参数:如下:

这里的jvm设置参数为:
-Xms900m -Xmx900m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:d://gc2.log

package com.test.main;

import java.util.ArrayList;
import java.util.List;

public class RubbishTest {

     static class A{
        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
    public static void main(String[] args) {
        try {
            List<A> list = new ArrayList<A>();
            while (true){
                A a = new A();
                list.add(a);
                System.out.println(System.currentTimeMillis());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

我们来看一下jvm回收情况:
在这里插入图片描述
再来看一下线程dump日志:

Thread 14 "Finalizer": (state = BLOCKED)

	at java.lang.Object.wait(Native Method)

	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)

	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)

	at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)



Thread 13 "Reference Handler": (state = BLOCKED)

	at java.lang.Object.wait(Native Method)

	at java.lang.Object.wait(Object.java:503)

	at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133)



Thread 1 "main": (state = BLOCKED)

	at java.nio.CharBuffer.wrap(CharBuffer.java:369)

	at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:265)

	at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125)

	at java.io.OutputStreamWriter.write(OutputStreamWriter.java:207)

	at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:129)

	at java.io.PrintStream.newLine(PrintStream.java:545)

	at java.io.PrintStream.println(PrintStream.java:751)

	at com.test.main.RubbishTest.main(RubbishTest.java:25)

我们发现main线程处于阻塞状态,再来看一下CPU情况:
在这里插入图片描述
在这里插入图片描述
我们再来看一下gc日志:

2020-10-13T11:55:07.501+0800: 1485.310: [Full GC [PSYoungGen: 226304K->226304K(267264K)] [ParOldGen: 585039K->585037K(614400K)] 811343K->811341K(881664K) [PSPermGen: 3256K->3256K(21504K)], 2.4311508 secs] [Times: user=18.81 sys=0.17, real=2.43 secs] 
2020-10-13T11:55:09.933+0800: 1487.741: [Full GC [PSYoungGen: 226304K->226304K(267264K)] [ParOldGen: 585039K->585037K(614400K)] 811343K->811341K(881664K) [PSPermGen: 3256K->3256K(21504K)], 2.4080620 secs] [Times: user=19.17 sys=0.06, real=2.41 secs] 
2020-10-13T11:55:12.341+0800: 1490.149: [Full GC [PSYoungGen: 226304K->226304K(267264K)] [ParOldGen: 585039K->585037K(614400K)] 811343K->811341K(881664K) [PSPermGen: 3256K->3256K(21504K)], 2.4003168 secs] [Times: user=18.89 sys=0.13, real=2.40 secs] 
2020-10-13T11:55:14.742+0800: 1492.550: [Full GC [PSYoungGen: 226304K->226304K(267264K)] [ParOldGen: 585039K->585037K(614400K)] 811343K->811341K(881664K) [PSPermGen: 3256K->3256K(21504K)], 2.4072049 secs] [Times: user=18.92 sys=0.19, real=2.41 secs] 
2020-10-13T11:55:17.150+0800: 1494.957: [Full GC [PSYoungGen: 226304K->226304K(267264K)] [ParOldGen: 585040K->585038K(614400K)] 811344K->811342K(881664K) [PSPermGen: 3256K->3256K(21504K)], 2.4165598 secs] [Times: user=18.88 sys=0.17, real=2.42 secs] 
2020-10-13T11:55:19.566+0800: 1497.374: [Full GC [PSYoungGen: 226304K->226304K(267264K)] [ParOldGen: 585040K->585038K(614400K)] 811344K->811342K(881664K) [PSPermGen: 3256K->3256K(21504K)], 2.4496853 secs] [Times: user=19.36 sys=0.06, real=2.45 secs] 
2020-10-13T11:55:22.016+0800: 1499.824: [Full GC [PSYoungGen: 226304K->226304K(267264K)] [ParOldGen: 585040K->585038K(614400K)] 811344K->811342K(881664K) [PSPermGen: 3256K->3256K(21504K)], 2.4136350 secs] [Times: user=18.77 sys=0.09, real=2.41 secs] 
2020-10-13T11:55:24.430+0800: 1502.238: [Full GC [PSYoungGen: 226304K->226304K(267264K)] [ParOldGen: 585040K->585038K(614400K)] 811344K->811342K(881664K) [PSPermGen: 3256K->3256K(21504K)], 2.4035978 secs] [Times: user=19.11 sys=0.20, real=2.40 secs] 
2020-10-13T11:55:26.833+0800: 1504.642: [Full GC [PSYoungGen: 226304K->226304K(267264K)] [ParOldGen: 585040K->585038K(614400K)] 811344K->811342K(881664K) [PSPermGen: 3256K->3256K(21504K)], 2.4074083 secs] [Times: user=18.75 sys=0.19, real=2.41 secs] 
2020-10-13T11:55:29.242+0800: 1507.050: [Full GC [PSYoungGen: 226304K->226304K(267264K)] [ParOldGen: 585041K->585039K(614400K)] 811345K->811343K(881664K) [PSPermGen: 3256K->3256K(21504K)], 2.3977490 secs] [Times: user=18.86 sys=0.17, real=2.40 secs] 
2020-10-13T11:55:31.639+0800: 1509.448: [Full GC [PSYoungGen: 226304K->226304K(267264K)] [ParOldGen: 585041K->585039K(614400K)] 811345K->811343K(881664K) [PSPermGen: 3256K->3256K(21504K)], 2.4077769 secs] [Times: user=18.64 sys=0.09, real=2.41 secs] 
2020-10-13T11:55:34.047+0800: 1511.856: [Full GC [PSYoungGen: 226304K->226304K(267264K)] [ParOldGen: 585041K->585039K(614400K)] 811345K->811343K(881664K) [PSPermGen: 3256K->3256K(21504K)], 2.4109829 secs] [Times: user=18.83 sys=0.13, real=2.41 secs] 
2020-10-13T11:55:36.458+0800: 1514.267: [Full GC [PSYoungGen: 226304K->226304K(267264K)] [ParOldGen: 585041K->585039K(614400K)] 811345K->811343K(881664K) [PSPermGen: 3256K->3256K(21504K)], 2.4132171 secs] [Times: user=18.81 sys=0.19, real=2.41 secs] 
2020-10-13T11:55:38.872+0800: 1516.680: [Full GC [PSYoungGen: 226304K->226304K(267264K)] [ParOldGen: 585041K->585039K(614400K)] 811345K->811343K(881664K) [PSPermGen: 3256K->3256K(21504K)], 2.4288084 secs] [Times: user=18.88 sys=0.22, real=2.43 secs] 
2020-10-13T11:55:41.301+0800: 1519.109: [Full GC [PSYoungGen: 226304K->226304K(267264K)] [ParOldGen: 585042K->585040K(614400K)] 811346K->811344K(881664K) [PSPermGen: 3256K->3256K(21504K)], 2.4301624 secs] [Times: user=18.92 sys=0.20, real=2.43 secs] 
2020-10-13T11:55:43.731+0800: 1521.540: [Full GC [PSYoungGen: 226304K->226304K(267264K)] [ParOldGen: 585042K->585040K(614400K)] 811346K->811344K(881664K) [PSPermGen: 3256K->3256K(21504K)], 2.4188353 secs] [Times: user=19.09 sys=0.17, real=2.42 secs] 
2020-10-13T11:55:46.151+0800: 1523.959: [Full GC [PSYoungGen: 226304K->226304K(267264K)] [ParOldGen: 585042K->585040K(614400K)] 811346K->811344K(881664K) [PSPermGen: 3256K->3256K(21504K)], 2.4330812 secs] [Times: user=19.26 sys=0.20, real=2.43 secs] 
2020-10-13T11:55:48.584+0800: 1526.392: [Full GC [PSYoungGen: 226304K->226304K(267264K)] [ParOldGen: 585042K->585040K(614400K)] 811346K->811344K(881664K) [PSPermGen: 3256K->3256K(21504K)], 2.4293412 secs] [Times: user=19.20 sys=0.20, real=2.43 secs] 
2020-10-13T11:55:51.013+0800: 1528.822: [Full GC [PSYoungGen: 226304K->226304K(267264K)] [ParOldGen: 585042K->585040K(614400K)] 811346K->811344K(881664K) [PSPermGen: 3256K->3256K(21504K)], 2.4657140 secs] [Times: user=19.47 sys=0.20, real=2.47 secs] 
2020-10-13T11:55:53.479+0800: 1531.287: [Full GC

这里通过GC日志可以看出来,jvm一直在努力的full gc,但是发现没有可以回收的对象,也没有抛出一个OOM异常,这就是所谓的内存泄露骗局**,发生原因是:eden区申请空间失败,转移至老年代,发生老年代空间不足,从而触发full gc,full gc无法回收堆空间,但是又没有达到超过提示OOM的范围(默认=2),这里我们根据gc日志来计算一下,占用空间=811344/881664=92%,剩余8%,大于默认的2%,这种情况下jvm会一直尝试full gc,但是不会抛出OOM;**

-------我们继续调整jvm参数,缩小到300M;-------
这里的jvm设置参数为:

-Xms300m -Xmx300m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:d://gc2.log

执行结果:

"C:\Program Files\Java\jdk1.7.0_71\bin\java.exe" -Xms300m -Xmx300m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:d://gc2.log "-javaagent:C:\IntelliJ IDEA2019.2.4\lib\idea_rt.jar=61101:C:\IntelliJ IDEA2019.2.4\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.7.0_71\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\jce.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\jfxrt.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\resources.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\rt.jar;E:\mytestProject\springtest\target\classes;D:\oms_resp\org\springframework\spring-core\4.3.19.RELEASE\spring-core-4.3.19.RELEASE.jar;D:\oms_resp\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;D:\oms_resp\org\springframework\spring-beans\4.3.19.RELEASE\spring-beans-4.3.19.RELEASE.jar;D:\oms_resp\org\springframework\spring-context\4.3.19.RELEASE\spring-context-4.3.19.RELEASE.jar;D:\oms_resp\org\springframework\spring-expression\4.3.19.RELEASE\spring-expression-4.3.19.RELEASE.jar;D:\oms_resp\org\springframework\spring-context-support\4.3.19.RELEASE\spring-context-support-4.3.19.RELEASE.jar;D:\oms_resp\org\springframework\spring-aop\4.3.19.RELEASE\spring-aop-4.3.19.RELEASE.jar;D:\oms_resp\org\springframework\spring-aspects\4.3.19.RELEASE\spring-aspects-4.3.19.RELEASE.jar;D:\oms_resp\org\aspectj\aspectjweaver\1.8.9\aspectjweaver-1.8.9.jar;D:\oms_resp\org\aspectj\aspectjrt\1.9.4\aspectjrt-1.9.4.jar" com.test.main.RubbishTest
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOf(Arrays.java:2245)
	at java.util.Arrays.copyOf(Arrays.java:2219)
	at java.util.ArrayList.grow(ArrayList.java:242)
	at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:216)
	at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:208)
	at java.util.ArrayList.add(ArrayList.java:440)
	at com.test.main.RubbishTest.main(RubbishTest.java:23)

Process finished with exit code 1

查看GC日志:

2020-10-13T14:02:39.849+0800: 0.134: [GC [PSYoungGen: 76800K->12787K(89600K)] 76800K->51795K(294400K), 0.0404025 secs] [Times: user=0.28 sys=0.03, real=0.04 secs] 
2020-10-13T14:02:39.899+0800: 0.185: [GC [PSYoungGen: 89587K->12784K(89600K)] 128595K->99716K(294400K), 0.0556522 secs] [Times: user=0.63 sys=0.00, real=0.06 secs] 
2020-10-13T14:02:39.967+0800: 0.252: [GC [PSYoungGen: 89584K->12768K(89600K)] 176516K->176643K(294400K), 0.0868302 secs] [Times: user=0.84 sys=0.05, real=0.09 secs] 
2020-10-13T14:02:40.054+0800: 0.339: [Full GC [PSYoungGen: 12768K->0K(89600K)] [ParOldGen: 163875K->152278K(204800K)] 176643K->152278K(294400K) [PSPermGen: 3237K->3236K(21504K)], 1.2966809 secs] [Times: user=5.44 sys=0.08, real=1.30 secs] 
2020-10-13T14:02:41.356+0800: 1.641: [GC [PSYoungGen: 28878K->12800K(89600K)] 181157K->181030K(294400K), 0.1553801 secs] [Times: user=1.56 sys=0.00, real=0.15 secs] 
2020-10-13T14:02:41.511+0800: 1.796: [Full GC [PSYoungGen: 12800K->0K(89600K)] [ParOldGen: 168230K->180866K(204800K)] 181030K->180866K(294400K) [PSPermGen: 3236K->3236K(21504K)], 1.3299680 secs] [Times: user=6.70 sys=0.03, real=1.33 secs] 
2020-10-13T14:02:42.852+0800: 3.137: [Full GC [PSYoungGen: 76800K->16895K(89600K)] [ParOldGen: 180866K->204715K(204800K)] 257666K->221610K(294400K) [PSPermGen: 3236K->3236K(21504K)], 0.7804965 secs] [Times: user=5.39 sys=0.08, real=0.78 secs] 
2020-10-13T14:02:43.640+0800: 3.925: [Full GC [PSYoungGen: 66503K->66288K(89600K)] [ParOldGen: 204715K->204715K(204800K)] 271218K->271004K(294400K) [PSPermGen: 3236K->3236K(21504K)], 1.3011720 secs] [Times: user=10.70 sys=0.09, real=1.30 secs] 
2020-10-13T14:02:44.941+0800: 5.226: [Full GC [PSYoungGen: 66288K->66288K(89600K)] [ParOldGen: 204715K->204697K(204800K)] 271004K->270986K(294400K) [PSPermGen: 3236K->3236K(21504K)], 0.8911681 secs] [Times: user=6.94 sys=0.09, real=0.89 secs] 
Heap
 PSYoungGen      total 89600K, used 68737K [0x00000000f9c00000, 0x0000000100000000, 0x0000000100000000)
  eden space 76800K, 89% used [0x00000000f9c00000,0x00000000fdf20780,0x00000000fe700000)
  from space 12800K, 0% used [0x00000000ff380000,0x00000000ff380000,0x0000000100000000)
  to   space 12800K, 0% used [0x00000000fe700000,0x00000000fe700000,0x00000000ff380000)
 ParOldGen       total 204800K, used 204697K [0x00000000ed400000, 0x00000000f9c00000, 0x00000000f9c00000)
  object space 204800K, 99% used [0x00000000ed400000,0x00000000f9be6680,0x00000000f9c00000)
 PSPermGen       total 21504K, used 3267K [0x00000000e8200000, 0x00000000e9700000, 0x00000000ed400000)
  object space 21504K, 15% used [0x00000000e8200000,0x00000000e8530f80,0x00000000e9700000)

这里的老年代放不下eden区gc的对象,抛出了OOM;我们继续验证一下,直接指定堆空闲的临界值为25

我们来通过参数来设置一下空闲堆大小的值:-XX:GCHeapFreeLimit

如下设置jvm参数:

-Xms900m -Xmx900m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:d://gc2.log **-XX:GCHeapFreeLimit=25**

-XX:GCHeapFreeLimit=25;代表剩余堆空间如果不足总大小的25%,那么就会抛出错误

我们再次运行,结果如下:

"C:\Program Files\Java\jdk1.7.0_71\bin\java.exe" -Xms900m -Xmx900m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:d://gc2.log -XX:GCHeapFreeLimit=25 "-javaagent:C:\IntelliJ IDEA2019.2.4\lib\idea_rt.jar=61267:C:\IntelliJ IDEA2019.2.4\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.7.0_71\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\jce.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\jfxrt.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\resources.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\rt.jar;E:\mytestProject\springtest\target\classes;D:\oms_resp\org\springframework\spring-core\4.3.19.RELEASE\spring-core-4.3.19.RELEASE.jar;D:\oms_resp\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;D:\oms_resp\org\springframework\spring-beans\4.3.19.RELEASE\spring-beans-4.3.19.RELEASE.jar;D:\oms_resp\org\springframework\spring-context\4.3.19.RELEASE\spring-context-4.3.19.RELEASE.jar;D:\oms_resp\org\springframework\spring-expression\4.3.19.RELEASE\spring-expression-4.3.19.RELEASE.jar;D:\oms_resp\org\springframework\spring-context-support\4.3.19.RELEASE\spring-context-support-4.3.19.RELEASE.jar;D:\oms_resp\org\springframework\spring-aop\4.3.19.RELEASE\spring-aop-4.3.19.RELEASE.jar;D:\oms_resp\org\springframework\spring-aspects\4.3.19.RELEASE\spring-aspects-4.3.19.RELEASE.jar;D:\oms_resp\org\aspectj\aspectjweaver\1.8.9\aspectjweaver-1.8.9.jar;D:\oms_resp\org\aspectj\aspectjrt\1.9.4\aspectjrt-1.9.4.jar" com.test.main.RubbishTest
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
	at com.test.main.RubbishTest.main(RubbishTest.java:23)

Process finished with exit code 1

这里抛出了GC错误,超过了GC最大限制;
我们来看一下GC日志:

2020-10-13T14:09:13.220+0800: 0.194: [GC [PSYoungGen: 230400K->38399K(268800K)] 230400K->148671K(883200K), 0.1209445 secs] [Times: user=0.92 sys=0.02, real=0.12 secs] 
2020-10-13T14:09:13.365+0800: 0.340: [GC [PSYoungGen: 204502K->38368K(268800K)] 314774K->271554K(883200K), 0.1493940 secs] [Times: user=1.22 sys=0.02, real=0.15 secs] 
2020-10-13T14:09:13.598+0800: 0.572: [GC [PSYoungGen: 268768K->38368K(268800K)] 623640K->542848K(883200K), 1.0427987 secs] [Times: user=9.20 sys=0.05, real=1.04 secs] 
2020-10-13T14:09:14.641+0800: 1.615: [Full GC [PSYoungGen: 38368K->0K(268800K)] [ParOldGen: 504480K->488097K(614400K)] 542848K->488097K(883200K) [PSPermGen: 3237K->3236K(21504K)], 3.9514668 secs] [Times: user=15.28 sys=0.08, real=3.95 secs] 
2020-10-13T14:09:18.612+0800: 5.586: [GC [PSYoungGen: 121758K->38400K(268800K)] 609856K->609457K(883200K), 0.5928956 secs] [Times: user=5.69 sys=0.02, real=0.59 secs] 
2020-10-13T14:09:19.205+0800: 6.179: [Full GC [PSYoungGen: 38400K->0K(268800K)] [ParOldGen: 571057K->609020K(614400K)] 609457K->609020K(883200K) [PSPermGen: 3236K->3236K(21504K)], 4.4758163 secs] [Times: user=21.38 sys=0.16, real=4.48 secs] 
2020-10-13T14:09:23.710+0800: 10.684: [Full GC [PSYoungGen: 230400K->230399K(268800K)] [ParOldGen: 609020K->487334K(614400K)] 839420K->717734K(883200K) [PSPermGen: 3236K->3236K(21504K)], 2.1423580 secs] [Times: user=16.30 sys=0.03, real=2.14 secs] 
2020-10-13T14:09:25.853+0800: 12.827: [Full GC [PSYoungGen: 230400K->230399K(268800K)] [ParOldGen: 487334K->487334K(614400K)] 717734K->717734K(883200K) [PSPermGen: 3236K->3236K(21504K)], 2.2490204 secs] [Times: user=16.31 sys=0.09, real=2.25 secs] 
2020-10-13T14:09:28.102+0800: 15.076: [Full GC [PSYoungGen: 230400K->230400K(268800K)] [ParOldGen: 487334K->487334K(614400K)] 717734K->717734K(883200K) [PSPermGen: 3236K->3236K(21504K)], 2.0458826 secs] [Times: user=16.00 sys=0.17, real=2.05 secs] 
2020-10-13T14:09:30.148+0800: 17.122: [Full GC [PSYoungGen: 230400K->230400K(268800K)] [ParOldGen: 487335K->487335K(614400K)] 717735K->717735K(883200K) [PSPermGen: 3236K->3236K(21504K)], 2.0365295 secs] [Times: user=15.92 sys=0.09, real=2.04 secs] 
2020-10-13T14:09:32.185+0800: 19.159: [Full GC [PSYoungGen: 230400K->230400K(268800K)] [ParOldGen: 487336K->487336K(614400K)] 717736K->717736K(883200K) [PSPermGen: 3236K->3236K(21504K)], 2.0638299 secs] [Times: user=16.41 sys=0.11, real=2.06 secs] 
2020-10-13T14:09:34.248+0800: 21.223: [Full GC [PSYoungGen: 230400K->230400K(268800K)] [ParOldGen: 487337K->487337K(614400K)] 717737K->717737K(883200K) [PSPermGen: 3236K->3236K(21504K)], 2.0800033 secs] [Times: user=16.14 sys=0.14, real=2.08 secs] 
2020-10-13T14:09:36.328+0800: 23.303: [Full GC [PSYoungGen: 230400K->230400K(268800K)] [ParOldGen: 487338K->487338K(614400K)] 717738K->717738K(883200K) [PSPermGen: 3236K->3236K(21504K)], 2.0775493 secs] [Times: user=15.98 sys=0.14, real=2.08 secs] 
2020-10-13T14:09:38.406+0800: 25.381: [Full GC [PSYoungGen: 230400K->230400K(268800K)] [ParOldGen: 487339K->487339K(614400K)] 717739K->717739K(883200K) [PSPermGen: 3236K->3236K(21504K)], 2.0283449 secs] [Times: user=15.75 sys=0.17, real=2.03 secs] 
2020-10-13T14:09:40.434+0800: 27.409: [Full GC [PSYoungGen: 230400K->230400K(268800K)] [ParOldGen: 487340K->487340K(614400K)] 717740K->717740K(883200K) [PSPermGen: 3236K->3236K(21504K)], 2.0488832 secs] [Times: user=15.92 sys=0.16, real=2.05 secs] 
2020-10-13T14:09:42.484+0800: 29.458: [Full GC [PSYoungGen: 230400K->230400K(268800K)] [ParOldGen: 487341K->487341K(614400K)] 717741K->717741K(883200K) [PSPermGen: 3236K->3236K(21504K)], 2.1725884 secs] [Times: user=16.39 sys=0.09, real=2.17 secs] 
2020-10-13T14:09:44.657+0800: 31.631: [Full GC [PSYoungGen: 230400K->230400K(268800K)] [ParOldGen: 487342K->487342K(614400K)] 717742K->717742K(883200K) [PSPermGen: 3236K->3236K(21504K)], 2.0455300 secs] [Times: user=15.75 sys=0.20, real=2.04 secs] 
2020-10-13T14:09:46.702+0800: 33.677: [Full GC [PSYoungGen: 230400K->230400K(268800K)] [ParOldGen: 487343K->487343K(614400K)] 717743K->717743K(883200K) [PSPermGen: 3236K->3236K(21504K)], 2.0976759 secs] [Times: user=16.55 sys=0.11, real=2.10 secs] 
2020-10-13T14:09:48.800+0800: 35.775: [Full GC [PSYoungGen: 230400K->230400K(268800K)] [ParOldGen: 487344K->487344K(614400K)] 717744K->717744K(883200K) [PSPermGen: 3236K->3236K(21504K)], 2.0533228 secs] [Times: user=15.63 sys=0.17, real=2.05 secs] 
2020-10-13T14:09:50.853+0800: 37.828: [Full GC [PSYoungGen: 230400K->230400K(268800K)] [ParOldGen: 487345K->487345K(614400K)] 717745K->717745K(883200K) [PSPermGen: 3236K->3236K(21504K)], 2.0544912 secs] [Times: user=15.95 sys=0.16, real=2.06 secs] 
2020-10-13T14:09:52.908+0800: 39.883: [Full GC [PSYoungGen: 230400K->230400K(268800K)] [ParOldGen: 487346K->487346K(614400K)] 717746K->717746K(883200K) [PSPermGen: 3236K->3236K(21504K)], 2.0304987 secs] [Times: user=16.13 sys=0.06, real=2.03 secs] 
2020-10-13T14:09:54.939+0800: 41.913: [Full GC [PSYoungGen: 230400K->230400K(268800K)] [ParOldGen: 487347K->487347K(614400K)] 717747K->717747K(883200K) [PSPermGen: 3236K->3236K(21504K)], 2.0330014 secs] [Times: user=15.86 sys=0.23, real=2.03 secs] 
2020-10-13T14:09:56.972+0800: 43.946: [Full GC [PSYoungGen: 230400K->230400K(268800K)] [ParOldGen: 487348K->487330K(614400K)] 717748K->717730K(883200K) [PSPermGen: 3236K->3236K(21504K)], 2.1918866 secs] [Times: user=16.78 sys=0.11, real=2.19 secs] 

还是来计算一下堆剩余空间大小,占用空间=717730/883200=81%,剩19%,小于上面jvm设置的25%,所以就抛出了OOM错误;

我们回到上面猜测的堆设置300m的设置,指定-XX:GCHeapFreeLimit=25;如下jvm设置:

-Xms300m -Xmx300m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:d://gc2.log -XX:GCHeapFreeLimit=25

继续运行结果如下:

"C:\Program Files\Java\jdk1.7.0_71\bin\java.exe" -Xms300m -Xmx300m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:d://gc2.log -XX:GCHeapFreeLimit=25 "-javaagent:C:\IntelliJ IDEA2019.2.4\lib\idea_rt.jar=63014:C:\IntelliJ IDEA2019.2.4\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.7.0_71\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\jce.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\jfxrt.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\resources.jar;C:\Program Files\Java\jdk1.7.0_71\jre\lib\rt.jar;E:\mytestProject\springtest\target\classes;D:\oms_resp\org\springframework\spring-core\4.3.19.RELEASE\spring-core-4.3.19.RELEASE.jar;D:\oms_resp\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;D:\oms_resp\org\springframework\spring-beans\4.3.19.RELEASE\spring-beans-4.3.19.RELEASE.jar;D:\oms_resp\org\springframework\spring-context\4.3.19.RELEASE\spring-context-4.3.19.RELEASE.jar;D:\oms_resp\org\springframework\spring-expression\4.3.19.RELEASE\spring-expression-4.3.19.RELEASE.jar;D:\oms_resp\org\springframework\spring-context-support\4.3.19.RELEASE\spring-context-support-4.3.19.RELEASE.jar;D:\oms_resp\org\springframework\spring-aop\4.3.19.RELEASE\spring-aop-4.3.19.RELEASE.jar;D:\oms_resp\org\springframework\spring-aspects\4.3.19.RELEASE\spring-aspects-4.3.19.RELEASE.jar;D:\oms_resp\org\aspectj\aspectjweaver\1.8.9\aspectjweaver-1.8.9.jar;D:\oms_resp\org\aspectj\aspectjrt\1.9.4\aspectjrt-1.9.4.jar" com.test.main.RubbishTest
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOf(Arrays.java:2245)
	at java.util.Arrays.copyOf(Arrays.java:2219)
	at java.util.ArrayList.grow(ArrayList.java:242)
	at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:216)
	at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:208)
	at java.util.ArrayList.add(ArrayList.java:440)
	at com.test.main.RubbishTest.main(RubbishTest.java:23)

Process finished with exit code 1

查看GC日志:

2020-10-13T14:50:03.236+0800: 0.135: [GC [PSYoungGen: 76800K->12771K(89600K)] 76800K->51819K(294400K), 0.0411236 secs] [Times: user=0.45 sys=0.01, real=0.04 secs] 
2020-10-13T14:50:03.288+0800: 0.187: [GC [PSYoungGen: 89571K->12784K(89600K)] 128619K->99724K(294400K), 0.0566552 secs] [Times: user=0.59 sys=0.03, real=0.06 secs] 
2020-10-13T14:50:03.356+0800: 0.256: [GC [PSYoungGen: 89584K->12776K(89600K)] 176524K->176595K(294400K), 0.0863521 secs] [Times: user=0.73 sys=0.00, real=0.09 secs] 
2020-10-13T14:50:03.443+0800: 0.342: [Full GC [PSYoungGen: 12776K->0K(89600K)] [ParOldGen: 163819K->152278K(204800K)] 176595K->152278K(294400K) [PSPermGen: 3237K->3236K(21504K)], 1.3309315 secs] [Times: user=5.70 sys=0.05, real=1.33 secs] 
2020-10-13T14:50:04.779+0800: 1.678: [GC [PSYoungGen: 28878K->12800K(89600K)] 181157K->181014K(294400K), 0.1707134 secs] [Times: user=1.63 sys=0.00, real=0.17 secs] 
2020-10-13T14:50:04.950+0800: 1.849: [Full GC [PSYoungGen: 12800K->0K(89600K)] [ParOldGen: 168214K->180866K(204800K)] 181014K->180866K(294400K) [PSPermGen: 3236K->3236K(21504K)], 1.3125388 secs] [Times: user=6.20 sys=0.08, real=1.31 secs] 
2020-10-13T14:50:06.273+0800: 3.171: [Full GC [PSYoungGen: 76800K->16895K(89600K)] [ParOldGen: 180866K->204715K(204800K)] 257666K->221610K(294400K) [PSPermGen: 3236K->3236K(21504K)], 0.7629433 secs] [Times: user=5.23 sys=0.13, real=0.76 secs] 
2020-10-13T14:50:07.043+0800: 3.942: [Full GC [PSYoungGen: 66503K->66288K(89600K)] [ParOldGen: 204715K->204715K(204800K)] 271218K->271004K(294400K) [PSPermGen: 3236K->3236K(21504K)], 1.2479725 secs] [Times: user=10.30 sys=0.08, real=1.25 secs] 
2020-10-13T14:50:08.291+0800: 5.191: [Full GC [PSYoungGen: 66288K->66288K(89600K)] [ParOldGen: 204715K->204697K(204800K)] 271004K->270986K(294400K) [PSPermGen: 3236K->3236K(21504K)], 0.8842482 secs] [Times: user=6.89 sys=0.11, real=0.89 secs] 
Heap
 PSYoungGen      total 89600K, used 68737K [0x00000000f9c00000, 0x0000000100000000, 0x0000000100000000)
  eden space 76800K, 89% used [0x00000000f9c00000,0x00000000fdf20780,0x00000000fe700000)
  from space 12800K, 0% used [0x00000000ff380000,0x00000000ff380000,0x0000000100000000)
  to   space 12800K, 0% used [0x00000000fe700000,0x00000000fe700000,0x00000000ff380000)
 ParOldGen       total 204800K, used 204697K [0x00000000ed400000, 0x00000000f9c00000, 0x00000000f9c00000)
  object space 204800K, 99% used [0x00000000ed400000,0x00000000f9be6680,0x00000000f9c00000)
 PSPermGen       total 21504K, used 3267K [0x00000000e8200000, 0x00000000e9700000, 0x00000000ed400000)
  object space 21504K, 15% used [0x00000000e8200000,0x00000000e8530f80,0x00000000e9700000)

计算结果还是跟上面一样:
堆占用空间为:270986/294400=92%,剩余8%,小于设定的25,抛出OOM;

------------------------------------------------分割线-------------------------------------------------------

有了垃圾回收,java会不会内存泄露

我们来看一段代码:

package com.test.main;

import java.util.ArrayList;
import java.util.List;

public class RubbishTest {

    static class A {
        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

    public static void main(String[] args) {
        List<A> list = new ArrayList<A>();
        for (int i = 0; i < 3; i++) {
            A a = new A();
            list.add(a);
            a = null;
        }
    }
}

解释:
       这里a指向堆中对象new A()的引用被置空,但是new A()对象还存在一个引用,这个引用就是list指向堆中的一个数组数组对象,数组对象是一片连续的内存空间,每个空间片存储着指向new A()的内存地址。

       所以这个new A()不会被垃圾回收器回收,但是这个对象在main栈帧空间被释放,list变量回收,list指向的对象被回收之后,内存当中的new A()就属于内存泄露。

       这时候的Gc Roots:a和list都被释放,没有一条路径可以找到new A()对象,那么这个new A()一定会被GC回收吗?不一定,如果调用了finalize()方法可以重新建议Gc Roots连接,只有一次的机会,第二次GC直接忽略,回收new A()对象。

以上仅是个人理解和记忆使用。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值