性能专题>匠心零度—JVM菜鸟进阶高手之路>
7
5

匠心零度—JVM菜鸟进阶高手之路分享专题

Jvm菜鸟进阶高手之路一原理篇:什么是Jvm?

谈到jvm首先需要谈的是,JAVA虚拟机规范:http://docs.oracle.com/javase/specs/jvms/se8/html/index.html,这个就类似jdbc规范一样,定义了一些规范,oracle有oracle的实现,mysql有mysql的实现,JAVA虚拟机规范也一样。

java虚拟机有很多,IBM、Apache Harmony等,每个都有些细节不一样,但是大体符合JAVA虚拟机规范的,由于Oracle收购SUN之后,Oralce主要有JRockit和Hotspot虚拟机了,后来将其进行整合了,不然维护两套麻烦,就和原来的struts1和struts2一样,Oralce主要是以Hotspot来的,把JRockit里面的一些优点也慢慢加入到其中。目前市面上Hotspot占用率是最高的,一般说到JAVA虚拟机基本都是Hotspot虚拟机。

JAVA8虚拟机规范地址:http://docs.oracle.com/javase/specs/jvms/se8/html/index.html,按照道理应该去阅读阅读的,虽然java语言与java虚拟机有密切的关系,但是两者是完全不同的内容,像Scala、Clojure、Groovy等语言都是跑在JAVA虚拟机上面的,可以产生各种各样的跨平台语言,除了语言特性不一样,他们可以共享JAVA虚拟机带来的跨平台性、垃圾回收器、以及即使编译。

看到这里都应该明白这些的JAVA虚拟机拥有的不是java语言规范定义的,java语言规范地址:http://docs.oracle.com/javase/specs/jls/se8/html/index.html,稍微解释下为什么用JAVA虚拟机就可以做到跨平台呢?依稀记得当时刚刚学习java的时候有句口号“一次编译,到处运行。”Java程序理想上,并不理会真正执行哪个平台,只要知道如何执行于JVM就可以了,至于JVM实际上如何与底层平台沟通,那是JVM自己的事。由于JVM实际上相当于Java程序的操作系统,JVM就负责了Java程序的各种资源管理。
我们要记住两点:

  • JVM就是Java程序的操作系统,JVM的可执行文件就是.class文件。
  • Java虚拟机屏蔽了操作系统之间的差异,但是不同的系统使用的虚拟机不同。

与其他语言相比,Java程序能够做到“编译一次,到处运行”,可见它的跨平台性非常强。其实JVM就是在操作系统层面有抽象了一层虚拟机,这样的好处可以屏蔽底层细节,有每个具体的平台的虚拟机实现即可,但是对外提供的是一致的(比如windows需要安装windows版的jdk,linux需要安装linux版的jdk就是这个原因,jvm虚拟机帮我们屏蔽到了底层的细节)。

一直有一个疑惑,Oracle的jdk和OpenJDK到底有什么关系呢?

Oracle/Sun JDK与OpenJDK的区别和联系如下: - OpenJDK原是SunMicrosystems公司为Java平台构建的Java开发环境(JDK)的开源版本,完全自由,开放源码。Sun Microsystems公司在2006年的JavaOne大会上称将对Java开放源代码,于2009年4月15日正式发布OpenJDK。甲骨文在 2010 年收购SunMicrosystem之后接管了这个项目。

  • oracle/Sun JDK里面包含的JVM是HotSpotVM,HotSpot VM只有非常非常少量的功能没有在OpenJDK里,那部分在Oracle内部的代码库里。这些私有部分都不涉及JVM的核心功能。所以说,Oracle/Sun JDK与OpenJDK其实使用的是同一个代码库。

  • 从一个Oracle内部员工的角度来看,当他要构建OracleJDK时,他同样需要先从http://hg.openjdk.java.net/签出OpenJDK,然后从Oracle内部的代码库签出私有的部分,放在OpenJDK代码下的一个特定目录里,然后构建。值得注意的是,Oracle JDK只发布二进制安装包,而OpenJDK只发布源码。

知道关系之后,其实很多就释然了,其实阿里的jdk就是基于OpenJDK定制的,所以看看OpenJDK对理解JVM很有帮助的,OpenJDK的github地址如下:https://github.com/dmlloyd/openjdk,既然都看见了OpenJDK的源码,那么是否有兴趣编译编译。

用final可以提高性能,为什么呢?

依稀记得以前老师说,用final可以提高性能,为什么呢?由于类的加载机制,关于一个*.class如何加载进来,如何一系列的操作后续会进行介绍,由于类的加载机制会提到一些热替换,热加载,以及阅读tomcat源码的时候可以了解到他是怎么处理加载的,由于final常量在准备阶段就初始化了,而并不是在初始化结点处理的,所以可以提高程序相应效率。

申明为final的情况:

  • 不需要重新赋值的变量,包括类属性、局部变量。
  • 对象参数前面加final,表示不允许修改引用的指向。
  • 类的方法不可以被重写。

备注: 此处有点错误,今天修改下,更能突出JVM的重要性了。 这个也是今天看见R大回复关于阿里代码规范才发现的。
image1.jpeg
学习了,看看JVM重要吧,今天在此纠正下,我查看新版阿里java代码规范也修改了,新版内容如下:
image2.jpeg
image3.jpeg

由于final关键字,在并发锁的时候,不可变的一些情况锁是无效的

比如锁一个Integer、Double、String等是不行的,你说这些你对JVM不了解能行吗?

JAVA虚拟机对各各数据类型的表示,所以引入了关于,原码,补码,反码等概念,为什么需要补码呢?

补码的好处:

  • 使用补码可以没有任何歧义的表示0。
  • 补码可以很好的参与二进制的运算,补码相加符号位参与运算, 这样就简单很多了。那就可以明白为什么数据溢出的概念了,经常看到
byte a=(byte)(127+1);
System.out.println(a);

如果不了解JVM怎么能懂,还有两个值相同的Integer型值进行==比较时:

Integer a=125;
Integer b=125;
Integer d=300;
Integer c=300;
System.out.println(c==d);
System.out.println(a==b);

运行结果为false、true?为什么呢? 查看源码:
image4.jpeg
这儿的IntegerCache有一个静态的Integer数组,在类加载时就将-128 到 127 的Integer对象创建了,并保存在cache数组中, 一旦程序调用valueOf 方法,如果i的值是在-128 到 127 之间就直接在cache缓存数组中去取Integer对象,超出 -128 ~ +127 范围的数字就要即时构建新的Integer对象,可以通过JVM参数 -XX:AutoBoxCacheMax来进行调整。 那么== 和equals的区别,== 是进行地址及值比较,无法对==操作符进行重载,而对于equals方法,Integer里面的equals方法 重写了Object的equals方法,所以,相同类型的包装类对象直接的值比较全部使用equals方法比较,并且能用基本数据类型 就应该用基本数据类型,这些你不了解JVM你那里知道呢?

根据IEEE754定义的浮点数的格式,所以涉及到钱的小数类型必须使用BigDecimal,禁止使用float和double,为什么呢?

不懂JVM可以?后续会讲。

慎用Object的clone方法拷贝对象,深拷贝,浅拷贝。

你不了解jvm模型咋知道呢?还有Object的finalize你不了解JVM怎么理解呢?

对于String的一些操作,String的文章最多。+运算符号

String str = "start";
 for(int i=0;i<100;i++){
     str = str +"hello";
 }

反编译出的字节码文件显示每次循环都会new出一个StringBuilder对象,然后进行append操作,最后通过toString方法返回String对象,造成内存资源浪费。

其他

HashMap、ArrayList、StringBuilder等的扩容机制,会浪费空间以及性能(可能存在跨代引用的问题),特别在并发情况下面可能会死锁,后续分享hashMap的cpu 100%情况,所以集合初始化时,尽量指定集合初始值大小,你不了解jvm怎么可以呢?还有很多框架,netty等对外内存(堆外空间),多线程相关ThreadLocal等,还有锁在java虚拟机中的实现优化,你不了解怎么可以呢?今天仅仅是开场白,后续会有系列基础知识文章出来。大家一起进步。

请先登录,感受更多精彩内容
快去登录吧,你将获得
  • 浏览更多精彩评论
  • 和开发者讨论交流,共同进步