Java His & JVM

Java之父James Gosling、BEA、SUN、ORACLE。 hotspot

2002年2月13日,JDK 1.4发布,工程代号为Merlin(灰背隼)。JDK 1.4是Java真正走向成熟的一个版本。JDK 1.4同样发布了很多新的技术特性,如正则表达式、异常链、NIO、日志类、XML解析器和XSLT转换器等。

2004年9月30日,JDK 1.5[1]发布,工程代号Tiger(老虎)。从JDK 1.2以来,Java在语法层面上的变换一直很小,而JDK .5在Java语法易用性上做出了非常大的改进。例如,自动装箱、泛型、动态注解、枚举、可变长参数、遍历循环(foreach循环)等语法特性都是在JDK1.5中加入的。在虚拟机和API层面上,这个版本改进了Java的内存模型(Java Memory Model,JMM)、提供了java.util.concurrent并发包等。

2006年12月11日,JDK 1.6发布,工程代号Mustang(野马)。在这个版本中,Sun终结了从JDK 1.2开始已经有8年历史的J2EE、J2SE、J2ME的命名方式,启用Java SE 6、Java EE6、Java ME 6的命名方式。JDK 1.6的改进包括:提供动态语言支持(通过内置Mozilla JavaScript Rhino引擎实现)、提供编译API和微型HTTP服务器API等。同时,这个版本对Java 虚拟机内部做了大量改进,包括锁与同步、垃圾收集、类加载等方面的算法都有相当多的改 动。

2009年2月19日,工程代号为Dolphin(海豚)的JDK 1.7完成了其第一个里程碑版本。JDK 1.7的主要改进包括:提供新的G1收集器(G1在发布时依然处于Experimental状态,直至2012年4月的Update 4中才正式“转正”)、加强对非Java语言的调用支持(JSR-292,这项特性到目前为止依然没有完全实现定型)、升级类加载架构等。

JAVA优势: JVM一次编写,到处运行,相对于c/c++,JVM避免了绝大多数的内存泄露和指针越界。天然支持多线程编程,各种强大的第三方框架。让程序员专注业务逻辑。认识这些技术运作的本质,是 自己思考“程序这样写好不好”的基础和前提,才能不惑。

Sun官方所定义的Java技术体系包括以下几个组成部分:

  • Java程序设计语言
  • 各种硬件平台上的Java虚拟机
  • Class文件格式
  • Java API类库
  • 来自商业机构和开源社区的第三方Java类库

JAVA CARD applet JAVA ME <-> android JAVA SE JAVA EE

Classic VM -> Exact VM -> HotSpot VM JRockit VM

内存泄露和内存溢出:

  • 堆 对象
  • 虚拟机栈 线程隔离
  • 本地方法栈 线程隔离
  • 方法区 常量 类 OutOfMemorryError StackOverFlowError

如32位的Windows限制为2GB。虚拟机提供了参数来控制Java堆和方法区的这两部分内存的最大值。剩余的内存为2GB(操作系统限制)减去Xmx(最大堆容量),再减去MaxPermSize(最大方法区容 量),程序计数器消耗内存很小,可以忽略掉。如果虚拟机进程本身耗费的内存不计算在内,剩下的内存就由虚拟机栈和本地方法栈“瓜分”了。每个线程分配到的栈容量越大,可以建立的线程数量自然就越少,建立线程时就越容易把剩下的内存耗尽。

GC策略:

  • 引用计数器 无法解决类似死锁的循环引用导致的不释放
  • 可达性分析 图论 标记 -> 筛选finalize() -> F-Queue

在JDK 1.2之后,Java对引用的概念进行了扩充,将引用分为强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)4种,这4种引用强度依次逐渐减弱。

方法区判断无用的类:

  • 该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例。
  • 加载该类的ClassLoader已经被回收。
  • 该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

在大量使用反射、动态代理、CGLib等ByteCode框架、动态生成JSP以及OSGi这类频繁自定义ClassLoader的场景都需要虚拟机具备类卸载的功能,以保证永久代不会溢出。

垃圾收集算法:

  • 标记清除算法
  • 复制算法
  • 标记整理算法
  • 分代收集算法

STOP THE WORLD

  • G1
  • CMS

平台无关性;二进制本地机器码Native Code 到 字节码ByteCode

语言无关性:JDK1.7开始的JSR-292支持其他语言运行于JVM,如Clojure,Groovy,JRuby,Jython,Scala. 只与.class文件格式关联,只要用相应编译器编译成.class文件即可。

Java 下一代 Groovy、Scala 和 Clojure

scala 诞生了spark和kafka两个重量级的产品。 golang 出品了docker。

.class类文件结构:

  • 8位字节为基础的二进制流
  • 伪结构:无符号数和表
  • 头4个字节为魔数Magic Number 0xCAFEBABE
  • 常量池
  • 访问标识

高效并发:

  • 主内存 工作内存 线程
  • 内存间交互操作
  • volatile变量
  • long和double的非原子性协定
  • 原子性、可见性、有序性
  • volatile关键字本身就包含了禁止指令重排序的语义
  • synchronized则是由“一个变量在同一个时刻只允许一条线程对其进行lock操作”这条规则获得的
  • “先行发生”(happens-before)的原则

Java语言定义了5种线程状态:

  • New
  • Runnable
  • Waiting
  • Timed Waiting
  • Blocked
  • Terminated

线程安全与锁优化: 当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那这个对象是线程安全的。

JAVA操作共享数据分为以下5类:

  • Immutable
  • 绝对线程安全
  • 相对线程安全 对对象单独的操作是线程安全的
  • 线程兼容
  • 线程对立 死锁风险

JAVA线程安全的实现方法:

  • 互斥同步 临界区、互斥量、信号量。synchronized关键字。
  • 重入锁(ReentrantLock)来实现同步
  • 非阻塞同步 CAS操作来避免阻塞同步
  • 无同步方案 可重入代码。可重入代码有一些共同的特征,例如不依赖存储在堆上的数据和公用的系统资源、用到的状态量都由参数中传入、不调用非可重入的方法等。
  • 线程本地存储 Web交互模型中的“一个请求对应一个服务器线程”(Thread-per-Request)的处理方式

锁优化: 适应性自旋(Adaptive Spinning)、锁消除(Lock Elimination)、锁粗化(Lock Coarsening)、轻量级锁(Lightweight Locking)和偏向锁(Biased Locking)