java的标量和聚合量_JVM 角度看代码优化

从JVM角度看,有这几种优化手段:

栈上分配:

把对上分配对象空间的行为转化成栈上分配,减少YGC,提供性能

同步省略

同步代码块锁消除

标量替换

为栈上分配提供了基础,和栈上分配时搭配做的

这几个优化手段需要JVM配置之外,写代码时还是需要配合的点,要不JVM优化也不会起作用,拜拜提供了优化手段而你不用

代码优化点太多了,我觉淂还是叉开来好些好理解一些......

栈上分配

栈上分配具体内容看:JVM 面试题【中级】,我就不再写一遍了

方法内部变量写的好一些,仔细一些以实现栈上分配的确有很大优势,这里跑个例子

public class Max {

public static void main(String[] args) {

long startTime = System.currentTimeMillis();

for (int i = 0; i < 10000000; i++) {

newValue();

}

long endTime = System.currentTimeMillis();

System.out.println("Time:" + (endTime - startTime));

try {

Thread.sleep(100000);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

public static void newValue() {

Dog dog = new Dog();

}

}

复制代码

关闭栈上分配

JVM配置:-Xms256m -Xmx256m -XX:-DoEscapeAnalysis -XX:+PrintGCDetails

log 日志:2次 YGC,耗时91毫秒,挺长了 w(゚Д゚)w

[GC (Allocation Failure) [PSYoungGen: 65536K->761K(76288K)] 65536K->769K(251392K), 0.0016895 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]

[GC (Allocation Failure) [PSYoungGen: 66297K->713K(76288K)] 66305K->721K(251392K), 0.0023094 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]

Time:91

复制代码内存快照:Dog 对象194万个,好多,这还是GC之后呀

GC快照:新生代64M里吃了47M,这样的短时间内大量创建的对象,要是在生命周期长一点的话,直接会爆到老年代里,估计会OOM,我这里堆内存才给了256M

启动栈上分配

JVM配置:-Xms256m -Xmx256m -XX:+DoEscapeAnalysis -XX:+PrintGCDetails

log 日志:没有GC,耗时7毫秒,时间差距相当大呀 O(≧口≦)O

Time:7

复制代码内存快照:Dog 对象只有7万个了,当然实际总是和理论有些差距啊,理论上堆内存现在一个Dog对象都没有才对的 ┑( ̄Д  ̄)┍

GC快照:新生代64M里吃了25M,和上面差距还是挺大的

总结

大家别看测试用例方法是执行1000万次,就意味没有实际意义啦,大家写的程序,分分钟你以为方法执行的少吗,能不能做到栈上分配堆性能是及其有意思的,差距大家都看到了吧

还没完啊

神转折来啦 (/// ̄皿 ̄)○~ 这是《深入理解JVM虚拟机里的原话》

逃逸分析的技术99年就出现了,一直到JDK1.6 Hotspot 才开始支持初步的逃逸分析,即便到现在这项技术仍未成熟,还有很大的改进余地。不成熟的原因是逃逸分析的计算成本非常高,甚至不能保证带来的性能优势会高于计算成本,在实际应用中,尤其是大型应用中反而发现逃逸发分析可能出现不稳定的状态。直到JDK7时才默认开启这项技术,服务模式的java程序才支持

上面例子效果明显,更多原因是因为下面会说的标量替换,没看到内存快照嘛,即便开启逃逸分析之后,Dog对象在堆内存中还是有非常多的对象存在,这和理论差距还是满大的

同步省略

懒得打字了,大家看图吧:

典型的例子:

public void test() {

Dog dog = new Dog();

synchronized (dog) {

System.out.println(dog);

}

}

复制代码

对于上面这个方法,JIT 动态编译器虽然会帮我们自动把锁消除了,但是在这是在运行阶段才会优化的,编译成字节码时还是能看到锁指令的

另外虽然有JIT优化,但是相比我们直接不写锁,优化之后的性能还是不如的,大家最好还是这样写,性能更好一些:

public void test() {

Dog dog = new Dog();

System.out.println(dog);

}

复制代码

标量替换

java 中:

标量: 是指一个无法再被分解成更小的数据的数据,比如基础数据类型

聚合量: 相对的就是那些还可以再分解的,比如对象就是

-XX:+EliminateAllocations JDK7开始默认是开启的

在JIT阶段,经过逃逸分析后,如果方法内对象符合栈上分配的规则,那会这个对象在栈上就会以标量的形式存储,可以进一步节省分配对象的操作

比如一个对象:

public class Dog extends Max {

public int age = 10;

public String name = "AA";

}

复制代码

经过标量替换后,一个Dog对象会以这种方式存储在局部变量表里:

public void test() {

// 一个 Dog 对象会变成下面这样

int age = 10;

String name = "AA";

}

复制代码标量替换为栈上分配提供了很好的基础 (⊙﹏⊙)

标量替换你要是在 JVM 配置里面关了,那栈上分配就不管用了,标量替换、栈上分配这2个必须都得设置才能起作用

PS:想骂娘,深度越深的技术,只是点都是这样拔出萝卜带出泥,一茬接一茬,目不暇接,越看越晕,要是资料再补全,跳着来,尼玛想死的心都有 (〃>目<)

关于找一找教程网

本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。

本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。

[JVM 角度看代码优化]http://www.zyiz.net/tech/detail-142658.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值