目录

Life in Flow

知不知,尚矣;不知知,病矣。
不知不知,殆矣。

X

内存分配

Java堆内存分配

Java堆分布图

对象分配遵循的规则

  • 对象主要分配在新生代的 Eden 区上。
  • 如果启动了本地线程分配缓冲,将按线程优先在 TLAB 上分配。
  • 少数情况下也可能会直接分配在老年代中。(新生代放不下的情况下、对象比较大的情况下[几乎占据From or To 区的全部,不如直接复制到老年代]。)

查看对象分配在哪个区域

//-verbose:gc -XX:+PrintGCDetails -XX:+UseSerialGC

public class TestJVMFirst {
    private static final int byteSize = 1024 * 1024;
    public static void main(String[] args) {
        byte[] bytes = new byte[40 * byteSize]; //40MB内存
    }
}

控制台输出

Heap
 PSYoungGen      total 76288K, used 47514K [0x000000076b000000, 0x0000000770500000, 0x00000007c0000000)
  eden space 65536K, 72% used [0x000000076b000000,0x000000076de66878,0x000000076f000000)
  from space 10752K, 0% used [0x000000076fa80000,0x000000076fa80000,0x0000000770500000)
  to   space 10752K, 0% used [0x000000076f000000,0x000000076f000000,0x000000076fa80000)
 ParOldGen       total 175104K, used 0K [0x00000006c1000000, 0x00000006cbb00000, 0x000000076b000000)
  object space 175104K, 0% used [0x00000006c1000000,0x00000006c1000000,0x00000006cbb00000)
 Metaspace       used 3509K, capacity 4498K, committed 4864K, reserved 1056768K
  class space    used 387K, capacity 390K, committed 512K, reserved 1048576K

新生代与老年代的垃圾收集

  • 新生代 GC (Minor GC):指发生在新生代的垃圾收集动作,因为 Java 对象大多都具备朝生夕灭的特性,所以 Minor GC 非常频繁,一般回收速度老年代
  • GC (Major GC/ Full GC):指发生在老年代的 GC,出现了 Major GC,经常会伴随至少一次的 Minor GC(但非绝对的,在 Parallel Scavenge 收集器的收集策略里就有直接进行 Major GC 的策略选择过程)。Major GC 的速度一般会比 Minor GC 慢 10 倍以上。

大对象的分配

 所谓的大对象是指,需要大量连续内存空间的 Java 对象,最典型的大对象就是那种很长的字符串以及数组。
 虚拟机提供了一个-XX: PretenureSizeThreshold 参数,令大于这个设置值的对象直接在老年代分配。这样做的目的是避免在 Eden 区及两个 Survivor 区之间发生大量的内存复制

配置参数含义

-verbose:gc -XX:+PrintGCDetails 开启GC日志打印
-Xms20 M 设置JVM初始内存为20M
-Xmx20 M 设置JVM最大内存为20M
-Xmn10 M 设置年轻代内存大小为10M

TestMaxObject

//-verbose:gc -XX:+PrintGCDetails -XX:+UseSerialGC -Xms20M -Xmx20M -Xmn10M -XX:PretenureSizeThreshold=3145728    
// 3MB
public class TestMaxObject {
    public static void main(String[] args) {
        byte[] bytes = new byte[1024*1024*10]; //10MB
    }
}

控制台输出

Heap
 def new generation   total 78656K, used 6995K [0x00000006c1000000, 0x00000006c6550000, 0x0000000716000000)
  eden space 69952K,  10% used [0x00000006c1000000, 0x00000006c16d4f68, 0x00000006c5450000)
  from space 8704K,   0% used [0x00000006c5450000, 0x00000006c5450000, 0x00000006c5cd0000)
  to   space 8704K,   0% used [0x00000006c5cd0000, 0x00000006c5cd0000, 0x00000006c6550000)
 tenured generation   total 174784K, used 10240K [0x0000000716000000, 0x0000000720ab0000, 0x00000007c0000000)
   the space 174784K,   5% used [0x0000000716000000, 0x0000000716a00010, 0x0000000716a00200, 0x0000000720ab0000)
 Metaspace       used 3509K, capacity 4498K, committed 4864K, reserved 1056768K
  class space    used 387K, capacity 390K, committed 512K, reserved 1048576K

逃逸分析

 逃逸分析的基本行为就是分析对象动态作用域。

  • 当一个对象在方法中被定义后,它可能被外部方法所引用,称为方法逃逸
public class TestEscape {
    public static Object obj;

    public void variableEscape(){
        obj = new Object(); //方法逃逸
    }
    
    public Object methodEscape(){
        return new Object(); //方法逃逸
    }
}
  • 甚至还有可能被外部线程访问到,譬如赋值给类变量或可以在其他线程中访问的实例变量,称为线程逃逸

栈上分配

 栈上分配就是把方法中的变量和对象分配到栈上,方法执行完后自动销毁,而不需要垃圾回收的介入,从而提高系统性能。

  • 开启逃逸分析(JDK1.8默认开启):就进行栈上分配。
  • 关闭逃逸分析:堆分配。

参数含义

-XX:+DoEscapeAnalysis开启逃逸分析(jdk1.8默认开启,其它版本未测试)
-XX:-DoEscapeAnalysis 关闭逃逸分析

// 当关闭逃逸分析:频繁日志输出分配内存失败
-verbose:gc -XX:+PrintGCDetails -XX:-DoEscapeAnalysis 关闭逃逸分析

TestEscape

public class TestEscape {

    public static Object obj;

    public void variableEscape(){
        obj = new Object(); //方法逃逸
    }

    public Object methodEscape(){
        return new Object(); //方法逃逸
    }

    public static void alloc(){
        byte[] b = new byte[2];
        b[0] = 1;
    }

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        for(int i =0; i < 100000000; i++){
            alloc();
        }
        long end = System.currentTimeMillis();
        System.out.println(end-start);
    }
}

控制台输出

-XX:-DoEscapeAnalysis (关闭逃逸分析,堆在分配)
	912 毫秒
-XX:+DoEscapeAnalysis(开启逃逸分析,栈上分配)
	5 毫秒

作者:Soulboy