Java架构介绍(三)
Java APIJava API是一套提供标准方式来访问主机系统资源的运行时库。当你运行一个java程序时,虚拟机会加载程序的class文件中引用到的Java API class文件。所有被加载的class文件(程序中的和Java API的)和被加载的动态链接库(含有native方法)组成了完整的Java虚拟机执行程序。Java API的class文件本质上是特定于主机平台
·
Java API
Java API是一套提供标准方式来访问主机系统资源的运行时库。当你运行一个java程序时,虚拟机会加载程序的class文件中引用到的Java API class文件。所有被加载的class文件(程序中的和Java API的)和被加载的动态链接库(含有native方法)组成了完整的Java虚拟机执行程序。
Java API的class文件本质上是特定于主机平台的。Java API的功能需要针对特定平台实现,通过调用native方法访问主机的本地资源。恰恰因为Java虚拟机和Java API是针对特定平台实现的,Java程序才能做到平台的无关性,如下图所示:
Java编程语言
Java语言允许你利用很多软件技术来编写层序:
- 面向对象
- 多线程
- 结构化错误处理
- 垃圾回收
- 动态链接
- 动态扩展
使用Java的一个最显著的原因之一就是它可以提高开发者的生产力,而java主要的缺点是可能会使执行速度变慢。Java是面向对象的语言,面向对象的编码方式可以促进代码的重用,这使得Java比C这类过程性的语言更吸引人。
在Java中,无法像C++一样,通过随意将指针转换成其他类型或者通过指针算法来直接访问内存。Java要求在处理对象时必须严格遵守类型规则。如果你有一个Mountain类对象的引用,你只能把它作为Mountain来操作。
Java通过垃圾回收器来管理内存,Java用new操作符来为对象在堆上分配内存,但是Java并没有相应的释放内存的操作符。在java中,只要你停止引用一个对象,一段时间后,垃圾回收器就会回收利用被这个对象占用的内存。
垃圾收集器使得java程序不需要显示地指定哪个对象的内存需要被释放。随着C++工程大小和复杂度的增长,对程序员来说,要确定哪个对象需要被释放变得愈发困难,或者确定一个对象是否已经被释放。当无用的对象没有释放时会导致内存泄露,当同一个对象意外地被多次释放时会导致内存损坏。这两种内存问题都会导致C++程序崩溃,并且很难追踪问题的确切来源。在java中,你不再需要显性地对内存进行释放,程序的设计变得更加简单。
对比其他如C++语言,Java的执行速度可能会慢些。然而,虽然在早期java的体验让开发者社区得出java执行速度慢的结论。但是虽然java的执行速度可能会慢,但速度慢并不是它固有的缺陷。现在,java虚拟机技术在执行性能上已经得到了很大的提升,与本地编译的c语言的性能达到同等水平。
在Java中,无法像C++一样,通过随意将指针转换成其他类型或者通过指针算法来直接访问内存。Java要求在处理对象时必须严格遵守类型规则。如果你有一个Mountain类对象的引用,你只能把它作为Mountain来操作。
Java通过垃圾回收器来管理内存,Java用new操作符来为对象在堆上分配内存,但是Java并没有相应的释放内存的操作符。在java中,只要你停止引用一个对象,一段时间后,垃圾回收器就会回收利用被这个对象占用的内存。
垃圾收集器使得java程序不需要显示地指定哪个对象的内存需要被释放。随着C++工程大小和复杂度的增长,对程序员来说,要确定哪个对象需要被释放变得愈发困难,或者确定一个对象是否已经被释放。当无用的对象没有释放时会导致内存泄露,当同一个对象意外地被多次释放时会导致内存损坏。这两种内存问题都会导致C++程序崩溃,并且很难追踪问题的确切来源。在java中,你不再需要显性地对内存进行释放,程序的设计变得更加简单。
架构的权衡
java虚拟机需要对以下几个方面需要进行权衡:
- 某些虚拟机的执行速度较慢
- 缺少对内存管理和线程分发的控制
- 平台无关性的实现
- 动态链接特性连同class文件和源文件之间的亲近关系
某些虚拟机的执行速度较慢
在1995年,第一台java虚拟机用一个解释器(一种性能很低的技术)执行字节码。不久后,即使编译器(just-in-time compiler)的出现显著地提高了java的性能,但仍然与本地编译的C++有一定的差距。而现在使用的自适应优化技术已经使得java程序的运行速度可以比肩于本地编译的C程序。
虽然最近在java上的研究进展是非常好的消息,但是问题是开发者并不总是可以选择哪个虚拟机来运行他们的程序。
一种介解决的办法是将java程序编译成单一可执行文件,也就是我们有时所说的提前编译,但这样做的代价是程序无法进行动态扩展,提前编译执行的是静态的非动态的链接。所以如果你的java程序不进行动态扩展,提前编译是一种提高保证java性能的方法。
缺少对内存管理和线程分发的控制
除了性能之外,java架构的另一个权折衷是缺少内存管理和线程分发的控制。垃圾收集可以使程序更加健壮,但同时也增加了程序运行性能的不确定性。你不能确保垃圾收集器什么时候进行垃圾回收,和垃圾收集需要消耗的时长。另外,java虚拟机规范中对线程分发描述得很笼统。对线程行为的宽松限制使得将java虚拟机移植到不同类型的硬件变得更简单。
平台无关性的实现
另一个权衡来自于java对平台无关性的实现。任何想要提供跨平台功能的API的内在困难是最低公共特性的问题。虽然操作系统间有很多重叠的功能,但是每个操作系统通常有一些自身特有的功能。如果一个功能只在一个操作系统中存在,那么API的设计者可能会决定不包含对这种功能的支持,如果一个性能在大多数的操作系统中存在,那么设计者可能会决定支持这个功能。
动态链接特性连同class文件和源文件之间的亲近关系
最后一个权衡源于java的动态链接特性连同它的class文件与java源程序的亲近关系。因为java程序是动态链接的,一个class对另一个class的引用是符号引用。在静态链接的可执行文件中,classes之间的引用是直接的指针或者偏移量。相比之下,在java的class文件中,对另一个class的引用以文本字符的形式阐明这个class的名字。如果这是一个对域的引用,域的名字和描述符(域的类型)也会被指定。如果这个对方法的引用,方法的名字和描述符(方法的返回类型,参数的数量和类型)会被指定。此外,java的class文件不仅包含对其他classes的域和方法的引用,还包含对自身域和方法的引用,class文件也可能包含某些可选择的调试信息。一个class文件的字符信息和字节码指令集与java语言之间的亲近关系,使得把java的class文件反编译成java源文件变得相当简单。
更多推荐
已为社区贡献1条内容
所有评论(0)