城市直播房产教育博客汽车
投稿投诉
汽车报价
买车新车
博客专栏
专题精品
教育留学
高考读书
房产家居
彩票视频
直播黑猫
投资微博
城市上海
政务旅游

能让java性能提升的JIT深度解析

5月1日 亡命徒投稿
  在从事Java开始的一段时间,那时候经常可以听到什么C的瞧不起写Java的,在一些群里也经常看到二个派的人经常互怼。Java能够这么流行与它的跨平台,语言无关性是分不开的,不管你是用Java,python还是Go,只要变成对应的标准字节码文件,那么JVM都是可以识别并执行的,但是那时候的Java之所以被C吐槽主要还是因为Java慢,为什么这么说呢。
  我们写的程序虽然能被JVM识别,但是不能被机器识别,程序要运行起来,还是得让机器能够识别你的程序,所以JVM还需要一个解释器,这个解释器就是将你的程序转换成机器能识别的指令,然后执行,如下图
  对于一个长期运行的Java进程来说,每次执行都要经过解释器将程序翻译成机器指令去执行,那么这个效率就不是很好,这也是为什么Java被吐槽慢因为缘故,所以为了解决这个问题,才出现了JIT。
  对于一些热点代码(经常被执行的,for循环)的一些代码,在运行时,JVM会将这些代码编译成机器可以执行的机器码,并缓存起来,这样下次执行这些代码的时候,就不需要再经过解释器去编译了,机器可以直接运行这段程序,提高性能,这个就被称为即时编译器,简称JIT编译器JIT的种类
  在JDK1。8中HotSpot虚拟机中,内置了二个JIT,分别为C1编译器和C2编译器
  C1编译器:是一个简单快速的编译器,主要关注点在于局部性的优化,适用于执行时间较短或者对启动性能有要求的程序,C1编译器几乎不会对代码进行优化
  C2编译器:是为长期运行的服务器端应用程序做性能调优的编译器,适用于执行时间较长或对峰值性能有要求的程序,根据各自的适配性,这种即时编译也被称为ServerCompiler,但是由于C2代码超级复杂,无人维护,所以才会开发Java编写的Graal编译器代替C2热点代码
  JIT会将一些热点代码编译成机器能够识别的机器码然后缓存起来,比如一些经常被调用的代码,还有for循环中的代码,那么JIT如何识别出哪些是热点代码呢??
  为什么说是一些热点代码缓存起来,而不是全部呢?因为缓存是需要空间存储的,可以通过以下命令查看该缓存的大小javaXX:PrintFlagsFinalversion复制代码
  JVM也提供了一个参数XX:ReservedCodeCacheSize来限制该缓存的大小,如果空间满了,JIT就无法继续编译,编译执行就会变成解释执行,程序也就会通过解释器去执行热点探测:
  热点探测也就是检查出那些热点代码,然后进行编译,热点探测是基于计数器的热点探测,也就是会统计每个方法被调用的次数,当次数达到一个阈值的时候,就会被认为是热点代码
  虚拟机为每个方法准备了两种计数器,方法调用计数器和回忆计数器,在确定JVM的运行参数之后,这二个计数器都会有各自的一个阈值,达到阈值就会出发JIT编译方法调用计数器:用于统计方法被调用的次数,客户端模式下默认是1500次,在服务端模式下默认是10000次(默认我们都是用服务端模式),我们可以使用以下命令查看javaXX:PrintFlagsFinalversion复制代码
  回边计数器:用于统计一个方法中循环体代码执行的次数,在字节码中遇到控制流向后跳转的指令称为回边,该值在服务端模式下默认是10700次,在JVM内存结构中是有一个程序计数器的,它表示的是字节码需要你执行的下一行指令的行号,当我们执行第一次循环之后,程序又回调到for循环的第一行执行,这个就叫回边for(inti0;i10000;i){}复制代码JIT是如何优化Java性能的方法内联
  方法内联的优化是指将被调用方法的代码复制到发起调用方法中,避免发生真实的方法调用,举个例子方法add1()要计算四个数加起来的和,然后又调用了add2()方法,其实根本没必要有add2()这个方法所以JIT会进行优化publicintadd1(inta,intb,intc,intd){returnadd2(a,b)add2(c,d);}publicintadd2(inta,intb){}优化后就一个方法就行了,也就是把add2()方法要执行的代码直接复制到add1()方法中执行,就不要去调用add2()这个方法了,这样就不存在方法调用,就一个方法就可以了publicintadd1(inta,intb,intc,intd){}复制代码
  为什么方法内联可以优化Java性能呢?我们知道一个方法的执行在JVM内存结构中虚拟机栈对应的就是入栈,方法结束就对应着出栈,出栈和入栈都是有性能消耗的,所以少一个方法执行就减少了一次对应的出栈和入栈,性能也就能够提升锁消除
  在非线程安全情况下,我们都会使用线程安全的容器,举个例子,比如字符串拼接的StringBuffer和StringBuilder,StringBuffer的方法被关键字synchornized修饰,所以性能会比StringBuilder差,但是在局部方法中二者的性能确实差不多的,因为在局部方法中是单线程访问的,不存在线程安全问题,jdk8默认情况下开启了锁消除publicstaticvoidmain(String〔〕args){longstartsbSystem。currentTimeMillis();for(inti0;i10000000;i){SBuilder(king,coco);}longendsbSystem。currentTimeMillis();System。out。println(StringBuilder话费的时间:(endsbstartsb));longstartsfSystem。currentTimeMillis();for(inti0;i10000000;i){SBuffer(king,coco);}longendsfSystem。currentTimeMillis();System。out。println(StringBuffer话费的时间:(endsfstartsf));}publicstaticvoidSBuilder(Stringstr1,Stringstr2){StringBuilderstringBuildernewStringBuilder();stringBuilder。append(str1);stringBuilder。append(str2);}publicstaticvoidSBuffer(Stringstr1,Stringstr2){StringBufferstringBuffernewStringBuffer();stringBuffer。append(str1);stringBuffer。append(str2);}复制代码
  花费的时间差不多
  然后我们可以通过启动参数XX:EliminateLocks关闭锁消除,XX:EliminateLocks开启锁消除
  关闭了锁消除之后,StringBuffer所话费的时间明显增加了很多,性能降低了,JIT在编译的时候发现如果使用了线程安全的容器,比如StringBUffer,但是发现程序不会存在线程并发问题,就会执行锁消除来提高程序的性能逃逸分析
  Java创建的大部分对象都是在堆中的,而不是全部的对象。逃逸分析技术就是在创建对象的时候判断这个对象是在保存在堆中还是保存在栈中,那么保存在栈中有什么好处呢??
  首先说说保存在堆中吧,JVM垃圾收集的主要对象就是堆,创建的对象在堆中保存,那么当你这个对象不用的时候就要被回收,我们知道垃圾回收是会消耗一定的性能的,但是如果你这个对象经过逃逸分析之后,发现这个对象可以在栈中分配,那么当你这个方法结束之后,也就是出栈,那么该对象自然就没了,也不需要垃圾收集器回收,这样就减少了垃圾收集器的工作,性能自然就能提升了
  那么什么是逃逸分析呢?我们创建了一个StringBuilder对象,但是这个对象只有在这个方法内部有效,该对象没有被返回出去也就是说没有方法需要a()方法创建的这个StringBuilder对象,所以这个StringBuilder对象不会发生逃逸publicStringa(){StringBuildersbnewStringBuilder();sb。append(123);return123;}这个StringBuilder对象就发生逃逸了,因为有其它方法需要b()方法创建的StringBuilder对象也就是说这个对象发生了逃逸publicStringBuilderb(){StringBuildersbnewStringBuilder();sb。append(123);}复制代码
  逃逸分析性能测试
  逃逸分析默认开启publicstaticvoidmain(String〔〕args){longstartSystem。currentTimeMillis();for(inti0;i50000000;i){createPeople();}longendSystem。currentTimeMillis();System。out。println(花费的时间是:(endstart));}publicstaticvoidcreatePeople(){PeoplepeoplenewPeople(10,coco);}staticclassPeople{ISpublicPeople(Integerage,Stringname){this。this。}}复制代码
  添加打印GC收集信息
  发现这么多对象很快就创建好了,并且没有垃圾收集日志的打印关闭逃逸分析
  关闭逃逸分析之后,所花费的时间显著上升
  并且我们可以加伤GC打印日志
  发现有GC的收集信息,因为对象都在堆中,所以才发生了GC,相反,开启逃逸分析技术的对象是随着栈的出入直接销毁的,不需要进行GC,所以性能会提升
  原文https:juejin。cnpost7120030108076736542
投诉 评论 转载

能让java性能提升的JIT深度解析在从事Java开始的一段时间,那时候经常可以听到什么C的瞧不起写Java的,在一些群里也经常看到二个派的人经常互怼。Java能够这么流行与它的跨平台,语言无关性是分不开的,不管……居家隔离,食疗指南,建议收藏一、普通人群,居家养生防护1、银耳雪梨百合羹组成:银耳、雪梨、百合、冰糖。功效:润肺祛火,滋补气血。制作方法:银耳用温水泡20分钟,将泡好的银耳去根,撕……电商产品经理必须要做的一件事仓库现场考察作为一名电商产品经理,若能对后端供应链环节及其运作机制加深了解,在进行产品设计时,电商产品经理则一定程度上可以拥有更宏观的设计视角。那么在供应链环节中,有哪些细节是电商PM需要……散文时光恬淡,秋日安闲作者:子墨日子缓缓,慢慢过着,有欣赏的风景,有剥离的时光,在岁月静好中,不知不觉过了一季又一季,在希望和失望之间,抬眸,九月已过大半。人间秋色渐浓,一场秋雨一场寒,……男篮欧洲杯神剧情!NBA也没有这样的剧本,法国锦鲤队进军四强同样的13s、同样的领先2分、同样的两罚不中、同样的被拖入加时、同样的惜败以上所述神奇的分别发生在男篮欧洲杯18决赛土耳其VS法国和14决赛意大利VS法国的比赛中。男篮欧……女性分享生育带来的影响,生育意味着什么?随着受教育程度的日益提升,多子多福的观念在当今早已不在是主流,甚至把孩子当作一种负担的存在。要知道思想的转变不是一朝一夕的,为什么从当初的多子多福变成了现在的样子,我们不……全红婵晒套装!管晨辰调侃有钱,隔离期玩游戏,再遇网络暴力经历了跳水世界杯斩获1金1银之后,全红婵回到上海进行隔离。运动员们为大赛备战很长的时间,比赛的压力也很大,如今比赛结束之后进行隔离,也有了难得的休息时间。15岁的全红婵很喜欢玩……草原天路雁门关,一个人的自驾游记(三)第五日7月7日草原天路早8点退房走人,今天计划去传说中有名的草原天路。就要离开此地了,事后想想,还是走的太匆匆,好不容易来一趟,好多该去的地方没走到,还是前期准备攻……5岁萌娃与父亲走散教科书式求助获民警点赞视频加载中。。。10月27日下午3点半左右,在上海静安区临汾路安业路口,一位小男孩在路人的帮助下,找到了执勤的临汾路派出所民警。小男孩今年5岁,下午和父亲出来购物。……我遇见个男人他总像夜一样沉默每当他来到我身边总会有鲜花和星空最美的秋作者:深沉我说不清一片树叶是用什么染红了自己等待了这么久只为与秋天作别我只是一个路过的人被美诱惑并不是惊艳倒映在水……客服电商外包公司亿澄客服电商外包公司是一家专门从事客服外包服务的公司。1:客服电商外包公司的背景亿澄客服电商外包公司指的是专业从事客户服务和电子商务领域外包的企业,目前国内外客服外……秋食之味美食和快乐,都在秋天一年四季,在季节的交错更替上,建始人捕捉食物的嗅觉格外灵敏。在吃的方面,湖北建始人从不吝啬在春夏的劳作,更不吝啬对秋收的垂涎。秋天树上的每一颗果实,都是对秋天的致敬……
年底还有哪些新机发布,等等党迎来胜利?正好侃球丨虽说过程惊心动魄可真架不住高速男篮打球人多这段木头里一定有虫流行发型魅力中发梨花头从京东金融大会谈如何打造一场拥有行业价值的会议老人哮喘的食疗方法行星撞地球导致恐龙灭绝?中国近地小行星防御系统来了君雅房车出发海南第12天,南澳岛潮州自制补水喷雾他的歌声在秋日的落基山上,转眼飘逝已25载生完孩子关节响怎么办10月22扫盘分析国际米兰客队惨遭虐杀?
windows7系统内存不够用虚拟内存大小修改步骤详情案子二次到检察院需要多久有结果热闻聚热点网 孩子学游泳的黄金时间各位家长知道吗男人的福音,中国好老婆榜样!刘秀为什么要杀欧阳歙欧阳歙被捕千人替他求情教育出了错责任并不全在父母,让孩子学会承担后果同样重要一般女孩吃春药有哪些反应呢?难倒老师的小学生儿大避母是真理!3条规矩妈妈请遵守,否则对儿子成长不好食用造句用食用造句大全四叶草小学四年级作文和时间赛跑读后感

友情链接:中准网聚热点快百科快传网快生活快软网快好知文好找江西南阳嘉兴昆明铜陵滨州广东西昌常德梅州兰州阳江运城金华广西萍乡大理重庆诸暨泉州安庆南充武汉辽宁