栈
堆
- TLAB
TLAB 是在 Eden 区域为每个线程分配的私有空间, 多线程同时在Eden区域分配空间可以避免线程线程安全问题, 也可以提高吞吐量, 避免加锁分配空间,默认的情况下 TLAB空间非常小占整个Eden区域的!%, TLAB内存不足是JVM会加锁分配空间
-XX:TLABWasteTargetPercent 参数可以设置大小
方法区
常量池
问题
- 堆是java对象分配的唯一选择吗?
逃逸分析其实就是如果这个变量没有超出本栈的就没有发送逃逸,在栈上直接创建这个对象栈结束了对象也就没有了, 也没不会存在于GC回收问题;
如果返回的这个对象超过了 这个栈帧的区域范围之内, 那么就发送了逃逸需要在堆空间创建对象;
// 未发生逃逸
public String test7(){
StringBuilder sb = new StringBuilder();
sb.append("1");
sb.append("2");
sb.append("3");
sb.append("4");
return sb.toString();
}
// 发送了逃逸
public StringBuilder test6(){
StringBuilder sb = new StringBuilder();
sb.append("1");
sb.append("2");
sb.append("3");
sb.append("4");
return sb;
}
栈上分配:
通过逃逸分析分析出代码不会超过这个栈帧空间那直接就在栈了创建对象了;
同步省略:
通过上面的逃逸分析结果, JIT来判断同步代码块是否被一个线程所使用的, 如果是, 那就直接删除锁, 也叫锁消除
// 优化前
public void test8(){
Object obj = new Object();
synchronized (obj) {
System.out.println(1);
}
}
// 优化后
public void test8(){
Object obj = new Object();
System.out.println(1);
}
标量替换:
标量就是java的原始数据类型, 无法再进行拆分了, 那我们吧对象里面包含很多的标量叫聚合量,JIT 阶段根据逃逸分析结果, 会把外界不在引用的对象直接替换为标量;
// 优化前
public void test9(){
Pint pint = new Pint(1,2);
System.out.println("x="+ pint.x+",y="+ pint.y);
}
class Pint{
public int x;
public int y;
public Pint(int x, int y) {
this.x = x;
this.y = y;
}
}
// 优化后
public void test9(){
int x = 1;
int y = 1;
System.out.println("x="+ x+",y="+ y);
}
class Pint{
public int x;
public int y;
public Pint(int x, int y) {
this.x = x;
this.y = y;
}
}
执行引擎
- 代码热点探测技术
JIT默认在 server模式下代码执行10000次会进行JIT编译成机器码, 在Clinet模式下默认是1500次,可以通过 -XX:CompileThreshold参数设置执行多少次进行JIT编译, 可以通过-XX:-UseCounterDecay来关闭热度衰减, 通过