垃圾回收相关概念
System.gc() 的理解
-
在默认情况下,通过System.gc()者Runtime.getRuntime().gc() 的调用,会显式触发Full GC,同时对老年代和新生代进行回收,尝试释放被丢弃对象占用的内存。
-
然而System.gc()调用附带一个免责声明,无法保证对垃圾收集器的调用(不能确保立即生效)
-
JVM实现者可以通过System.gc() 调用来决定JVM的GC行为。而一般情况下,垃圾回收应该是自动进行的,**无须手动触发,否则就太过于麻烦了。**在一些特殊情况下,如我们正在编写一个性能基准,我们可以在运行之间调用System.gc()
代码示例:手动执行 GC 操作
public class SystemGCTest {
public static void main(String[] args) {
new SystemGCTest();
System.gc();//提醒jvm的垃圾回收器执行gc,但是不确定是否马上执行gc
//与Runtime.getRuntime().gc();的作用一样。
// System.runFinalization();//强制调用使用引用的对象的finalize()方法
}
//如果发生了GC,这个finalize()一定会被调用
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("SystemGCTest 重写了finalize()");
}
}
输出结果不确定:有时候会调用 finalize() 方法,有时候并不会调用
SystemGCTest 重写了finalize()
或
空
手动 GC 理解不可达对象的回收行为
//加上参数: -XX:+PrintGCDetails
public class LocalVarGC {
public void localvarGC1() {
byte[] buffer = new byte[10 * 1024 * 1024];//10MB
System.gc();
}
public void localvarGC2() {
byte[] buffer = new byte[10 * 1024 * 1024];
buffer = null;
System.gc();
}
public void localvarGC3() {
{
byte[] buffer = new byte[10 * 1024 * 1024];
}
System.gc();
}
public void localvarGC4() {
{
byte[] buffer = new byte[10 * 1024 * 1024];
}
int value = 10;
System.gc();
}
public void localvarGC5() {
localvarGC1();
System.gc();
}
public static void main(String[] args) {
LocalVarGC local = new LocalVarGC();
//通过在main方法调用这几个方法进行测试
local.localvarGC1();
}
}
JVM参数:
-Xms256m -Xmx256m -XX:+PrintGCDetails -XX:PretenureSizeThreshold=15m
1、第四个参数是设置大对象直接进入老年代的阈值,由于我的电脑8G和视频里老师的电脑16G不太一样。我测试的时候10M的数组都是直接进入到了老年代,为了保持一样的效果,我同时设置了堆内存和大对象阈值,尽量和宋红康老师保持一致
2、我也查过了大对象阈值的默认值
我不太懂这个默认值为啥是0,我猜测可能是代表什么比例,目前也没有搜到相关的东西。这个不太重要,暂时就没有太深究,希望读者有知道的可以告知我一声。
看不懂GC日志请看笔者的 堆那篇文章
1、调用 localvarGC1() 方法
执行 System.gc() 仅仅是将年轻代的 buffer 数组对象放到了老年代,buffer对象仍然没有回收
[GC (System.gc()) [PSYoungGen: 15492K->10728K(76288K)] 15492K->11000K(251392K), 0.0066473 secs] [Times: user=0.08 sys=0.02, real=0.01 secs]
[Full GC (System.gc()) [PSYoungGen: 10728K->0K(76288K)] [ParOldGen: 272K->10911K(175104K)] 11000K->10911K(251392K), [Metaspace: 3492K->3492K(1056768K)], 0.0097940 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
Heap
PSYoungGen total 76288K, used 655K [0x00000000fab00000, 0x0000000100000000, 0x0000000100000000)
eden space 65536K, 1% used [0x00000000fab00000,0x00000000faba3ee8,0x00000000feb00000)
from space 10752K, 0% used [0x00000000feb00000,0x00000000feb00000,0x00000000ff580000)
to space 10752K, 0% used [0x00000000ff580000,0x00000000ff580000,0x0000000100000000)
ParOldGen total 175104K, used 10911K [0x00000000f0000000, 0x00000000fab00000, 0x00000000fab00000)
object space 175104K, 6% used [0x00000000f0000000,0x00000000f0aa7d08,0x00000000fab00000)
Metaspace used 3498K, capacity 4498K, committed 4864K, reserved 1056768K
class space used 387K, capacity 390K, committed 512K, reserved 1048576K
2、调用 localvarGC2() 方法
由于 buffer 数组对象没有引用指向它,执行 System.gc() 将被回收
[GC (System.gc()) [PSYoungGen: 15492K->808K(76288K)] 15492K->816K(251392K), 0.0294475 secs] [Times: user=0.00 sys=0.00, real=0.04 secs]
[Full GC (System.gc()) [PSYoungGen: 808K->0K(76288K)] [ParOldGen: 8K->640K(175104K)] 816K->640K(251392K), [Metaspace: 3385K->3385K(1056768K)], 0.0054210 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]