本文共 5824 字,大约阅读时间需要 19 分钟。
通过idea 的-VM参数设置,如下图:
详情请看 Ctrl+F 搜索 -Xms
通过JVM参数来设置堆空间的初始值
通过JVM参数来设置堆空间的最大值
堆的初始大小(以字节为单位)。
k
或K
表示千字节,m
或M
表示兆字节,g
或G
表示千兆字节。-Xmn
选项或-XX:NewSize
选项设置年轻代的堆的初始大小。开发中建议将初始堆内存和最大的堆内存设置成相同的值。
打印GC过程的细节
添加代码测试**
public class HeapSpaceInitial { public static void main(String[] args) { //返回Java虚拟机中的堆内存总量 long initialMemory = Runtime.getRuntime().totalMemory() / 1024 / 1024; //返回Java虚拟机试图使用的最大堆内存量 long maxMemory = Runtime.getRuntime().maxMemory() / 1024 / 1024; System.out.println("-Xms : " + initialMemory + "M"); System.out.println("-Xmx : " + maxMemory + "M"); System.out.println("系统内存大小为:" + initialMemory * 64.0 / 1024 + "G"); System.out.println("系统内存大小为:" + maxMemory * 4.0 / 1024 + "G"); }}
打印GC日志(详情信息看后期博客)
-XX:NewRatio:设置新生代与老年代的比例。
设置新老一代大小之间的比率。默认情况下,此选项设置为2。下面的示例演示如何将年轻/老人比率设置为1:1(这里就是年轻代占堆空间1:2,老年的占1:2)
-XX:NewRatio =3 //设置老年代占堆空间的3:4
-XX:SurvivorRatio:设置新生代中Eden区与survivor区的比例
-XX: -UseAdaptivesizePolicy :关闭自适应的内存分配策略( 暂时用不到)
Xmn:设置新生代的空间的大小。 ( 一般不设置)
年轻代GC(Minor GC) 触发机制:
老年代GC (Major GC/Fu11 GC)触发机制:
Fu11 GC,触发Fu1l GC执行的情况有如下五种:
如果对象在Eden(伊甸园区)出生并经过第一次MinorGC 后仍然存活,并且能被Survivor
容纳的话,将被移动到Survivor空间中,并将对象年龄设为1 。对象在 Survivor区中每熬过一次MinorGC ,年龄就增加1 岁,当它的年龄增加到- -定 程度(默认为15岁,其实每个JVM、每个GC都有所不同)时,就会被晋升到老年代 中。对象晋升老年代的年龄阈值,可以通过选项-XX: MaxTenuringThreshold来设置。
针对不同年龄段的对象分配原则如下所示:|
优先分 配到Eden
大对象直接分配到老年代
动态对象年龄判断
空间分配担保
为什么有TLAB ( Thread Local Allocation Buffer ) ?
什么是TLAB ?
TLAB分配过程:
-XX: +PrintFlagsInitial :查看所有的参数的默认初始值
-XX:+PrintFlagsFinal : 查看所有的参数的最终值(可能会存在修改,
不再是初始值)-Xms:初始堆空间内存 (默认为物理内存的1/64)
-Xmx:最大堆空间内存(默认为物理内存的1 /4)
Xmn: 设置新生代的大小。(初始值及最大值)
XX: +DoEscapeAnalysis ; 开启逃逸分析
XX:NewRatio:配置新生代与老年代在堆结构的占比
-XX:SurvivorRatio:设置新生代中Eden和SO/S1空间的比例
-XX:MaxTenuringThreshold:设置新生代垃圾的最大年龄
-XX: +PrintGCDetails:输出详细的GC处理日志
-XX:HandL ePromotionFailure:是否设置空间分配担保
-XX:+EliminateAllocations: 开启标量替换
/** * 逃逸分析 * * 如何快速的判断是否发生了逃逸分析,大家就看new的对象实体是否有可能在方法外被调用。 */public class EscapeAnalysis { public EscapeAnalysis obj; /* 方法返回EscapeAnalysis对象,发生逃逸 */ public EscapeAnalysis getInstance(){ return obj == null? new EscapeAnalysis() : obj; } /* 为成员属性赋值,发生逃逸 */ public void setObj(){ this.obj = new EscapeAnalysis(); } //思考:如果当前的obj引用声明为static的?仍然会发生逃逸。 /* 对象的作用域仅在当前方法中有效,没有发生逃逸 */ public void useEscapeAnalysis(){ EscapeAnalysis e = new EscapeAnalysis(); } /* 引用成员变量的值,发生逃逸 */ public void useEscapeAnalysis1(){ EscapeAnalysis e = getInstance(); //getInstance().xxx()同样会发生逃逸 }}
使用逃逸分析,编译器可以对代码做如下优化:
一、栈上分配:
将堆分配转化为栈分配。如果一个对象在子程序中被分配,要使指向该对象的指针永远不会逃逸,对象可能是栈分配的候选,而不是堆分配。
二、同步省略:
如果一个对象被发现只能从一个线程被访问到,那么对于这个对象的操作可以不考虑同步。
三、分离对象或标量替换:
有的对象可能不需要作为一个连续的内存结构存在也可以被访问到,那么对象的部分(或全部)可以不存储在内存,而是存储在CPU寄存器中。
转载地址:http://oqqzi.baihongyu.com/