目录

一、堆空间参数设置(常用参数)

二、堆是分配对象存储的唯一选择嘛?

三、逃逸分析

3.1、参数设置


一、堆空间参数设置(常用参数)

参数官方文档:java (oracle.com)https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html

1、 -XX:+PrintFlagsInitial :查看所有的参数的默认初始值

参考代码:

public class HeapAddTest {
    public static void main(String[] args) {
        System.out.println("测试开始");
    }
}

配置参数:

java 参数配置 堆外内存 java设置堆内存_jvm

打印结果:

java 参数配置 堆外内存 java设置堆内存_java 参数配置 堆外内存_02

2、 -XX:+PrintFlagsFinal :查看所有的参数的最终值(可能会存在修改,不再是初始值)。

java 参数配置 堆外内存 java设置堆内存_jvm_03

 3、-Xms:初始堆空间内存(默认为物理内存的1/64),-Xmx:最大堆空间内存(默认为物理内存的1/4),-Xmn:设置新生代的大小。(初始值及最大值)。

4、-XX:NewRatio:配置新生代与老年代在堆结构的占比。

5、-XX:SurvivorRatio:设置新生代中Eden和s0/s1空间的比例

6、-XX:MaxTenuringThreshold:设置新生代垃圾的最大年龄

7、-XX:+PrintGcDetails:输出详细的Gc处理日志:打印gc简要信息:1-XX:+PrintGC ②、 -verbose: gc

8、-XX :HandlePromotionFailure:是否设置空间分配担保,jdk6以后没有太大意义了。

二、堆是分配对象存储的唯一选择嘛?

1、随着JIT编译期的发展与逃逸分析技术逐渐成熟,栈上分配、标量替换优化技术将会导致一些微妙的变化,所有的对象都分配到堆上也渐渐变得不那么“绝对”了。

2、在Java虚拟机中,对象是在Java堆中分配内存的,这是一个普遍的常识。但是,有一种特殊情况,那就是如果经过逃逸分析(Escape Analysis)后发现,一个对象并没有逃逸出方法的话,那么就可能被优化成栈上分配。这样就无需在堆上分配内存,也无须进行垃圾回收了。这也是最常见的堆外存储技术。

3、此外,前面提到的基于OpenJDK深度定制的TaoBaoVM,其中创新的GCIH (GC invisible heap)技术实现off-heap,将生命周期较长的Java对象从heap中移至heap外,并且GC不能管理GCIH内部的Java对象,以此达到降低GC的回收频率和提升GC的回收效率的目的。

三、逃逸分析

1、如何将堆上的对象分配到栈,需要使用逃逸分析手段。

2、这是一种可以有效减少Java程序中同步负载和内存堆分配压力的跨函数全局数据流分析算法。|

3、通过逃逸分析,Java Hotspot编译器能够分析出一个新的对象的引用的使用范围从而决定是否要将这个对象分配到堆上。

4、逃逸分析的基本行为就是分析对象动态作用域: ①、当一个对象在方法中被定义后,对象只在方法内部使用,则认为没有发生逃逸。②、当一个对象在方法中被定义后,它被外部方法所引用,则认为发生逃逸。例如作为调用参数传递到其他地方中。

参考代码:

public class EscapeAnalysis {
    public EscapeAnalysis escapeAnalysis;

    /**
     * 方法返回对象发生逃逸
     * @return
     */
    public EscapeAnalysis getInstance(){
        return escapeAnalysis == null ? new EscapeAnalysis() : escapeAnalysis;
    }

    /**
     * 为属性赋值发生逃逸
     * @param escapeAnalysis
     */
    public void setEscapeAnalysis(EscapeAnalysis escapeAnalysis) {
        this.escapeAnalysis = new EscapeAnalysis();
    }

    /**
     * 对象仅作用域仅在当前方法中有效,没有发生逃逸
     */
    public void useEscapeAnalysis(){
        EscapeAnalysis e = new  EscapeAnalysis();
    }

    /**
     * 引用成员变量的值,发生逃逸
     */
    public void getuseEscapeAnalysis(){
        EscapeAnalysis e = getInstance();
    }
}

总结:快速判断是否发生逃逸,观察new的对象是否存在方法外调用。开发中能使用局部变量,尽量不要使用在方法外定义。

3.1、参数设置

   在JDK 6u23版本之后,HotSpot中默认就已经开启了逃逸分析。如果使用的是较早的版本,开发人员则可以通过:①、选项“-XX: +DoEscapeAnalysis"显式开启逃逸分析。②、通过选项“-XX: +PrintEscapeAnalysis”查看逃逸分析的筛选结果。