没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
Error! Reference source not found.
1 概述
Java在大行其道的同时也在为自己与生俱来的缺陷不断的努力着,我们有理由相信
Java的开发设计者们真是一群天才。构成Java技术的基石就是JVM的虚拟机技术,这时的
Java已经不再是一门简单的语言,而是语言、开发包JDK与虚拟机的完美结合,而这里面的
虚拟机则是融合了编译技术、CPU技术的Java存在的基础所在。既然那么多的优秀的人为
提升虚拟机性能做了那么多的工作,我们有什么理由不去充分利用这些宝贵的资源呢?本文
就是试图从原理分析到参数应用上来帮助读者更大的发挥Java虚拟机的性能极限,使这样
一个优秀的产品更好地为我们服务。
2 JAVA虚拟机运行机制概览
2.1 运行时分析
首先让我们来看看所谓的Java虚拟机在运行起来后是什么样子的,从外面来看一个Java
虚拟机的运行实例就是一个运行着的Java进程,Java进程在启动过程中做了如下工作,一、
根据环境变量的设置或者Java进程的命令行参数将Java Class字节码加载到内存中,这样的
Java字节码是Java虚拟机所能够识别的虚拟机指令的集合,Java虚拟机在解释执行字节指
令的同时,根据某些代码的使用频率,将其中一部分字节码翻译成机器能够识别的二进制指
令保存在内存中,在以后对这部分代码的调用,则由Java虚拟机的代码控制CPU直接执行
内存中的这部分二进制指令,这个就是Java虚拟机的热点编译技术。而在早期的Java虚拟
机实现中是采用全部字节程序解释执行的方式,后来发展了Java静态编译技术,这种技术
是在Java程序编译成字节码后,由一个本地编译器将这些字节码编译成二进制可执行文件,
这种编译技术不利于程序的移植。再后来发展的Java的动态编译技术,这时的编译过程是
在Java装载字节码文件时进行的,而此时的问题是Java在启动时需要花费很长的时间来编
译这些字节码。直到最后流行的Hotspot技术的出现,此时编译仅仅运行于少部分代码。按
照80/20的原则,程序的百分之80的时间仅仅运行其百分之20的代码,这样一个能够平衡启
动时间、移植性的中间方法解决了人们的大部分问题。
之后,让我们看看Java虚拟机的内部体系结构,从下面的体系机构图来看,Java的Class
字节码文件经由类加载子系统加载到内存中时,虚拟机根据文件内容将类的方法和数据加载
到称为方法区的地方,堆是用来为运行时类实例提供存放场所的地方,这样的堆也称之为
对象堆空间。而Java栈和PC计数器则是为了Java线程而设计的,每一个Java线程一旦创建,
它都将得到一个属于他自己的PC计数器(程序计数器指针,类似于CPU中的IP指令指针计
数器)以及一个线程栈,在新版本Java Hotspot VM中是没有本地方法栈和线程栈之分的,
只有一个线程栈的模块。这样每个线程的运行都是在属于自己栈空间内的,而所有的线程则
共享着一个堆空间。当然在线程实现上不同的Java虚拟机的内部实现可能各有不同,有的
自是直接将Java线程和操作系统内核线程绑定起来的,在虚拟机进程内部创建一个Java线
程虚拟机就会请求操作系统为该一个进程创建一个内核线程,将线程之间的调度交给了操作
系统内核来完成。而在早期的Java虚拟机一些实现中,Java线程对于操作系统来说是不可
见,而是由应用层来完成线程调度,对于操作系统来说仅仅是一个单线程的进程。
图1 Java虚拟机的内部体系结构
Java虚拟机在运行时,由主线程开始解释执行类文件中的指令,主线程在自己的线程
栈中存放临时变量、参数变量等,一旦碰到生成新对象的new操作时,就会在堆空间内申请
一块内存存放该类对象,而一旦程序从一个方法中退出后(退回到一个方法栈的栈底),虚
拟机程序并不会立即释放Heap空间内的这块内存,这就是与C/C++程序所不同的地方,因
为C/C++程序被加载程序的操作系统调用装载到内存中之后,程序的内存是由操作系统为之
分配的4G的虚拟内存空间,而堆空间的使用也是由程序的内存分配子系统(malloc)来完
成的,而这个子系统仅仅是向程序员提供了申请/释放内存的调用接口,查看C/C++编译器
生成的汇编代码你会发现,如果你在一个函数中申请了一块内存,而没有在函数退出的地方
没有释放的话,这块内存则会永远放在堆中,而对于你在函数中生明的类变量对象来说(非
new来申请的指针对象),这个类对象的内存是在程序栈空间中分配的,一旦这个函数释放
则对象空间自动释放,这样的内存泄漏正是Java竭力避免的,Java从发明之初就是考虑着
如何将大部分应用程序员从繁重的内存管理工作中解脱出来,而由Java虚拟机使用称之为
GC垃圾收集的模块来完成内存空间的管理。Java虚拟机在启动时会根据-Xms的参数值向操
作系统一次性申请一块内存空间作为自己的堆,而随着后续程序的运行中内存需求的增加,
则再向操作系统申请更多的内存加到自己的堆空间中。这个堆空间的最大值就是由-Xms指
定的。一旦Java虚拟机发现应用程序申请的内存超过了堆内存的最大空间的话,Java就会
抛出一个超出堆空间的异常。而当虚拟机在启动时如果申请不到足够的内存的话,则同样会
抛出一个异常,启动失败。所有这些工作都是由Java虚拟机的内存管理模块来完成的,而Java
的内存管理功能中最俱特色和重要的垃圾收集功能GC则是按照下面机制运行的。
2.2 垃圾收集和线程同步
Java的垃圾收集器就像一个兢兢业业的仓库保管员,他管理着虚拟机堆空间的清扫工
作,接着上面描述的,一旦一个函数退出了它的栈,在该函数内声明的一个Java对象则会
留在Java堆空间内,那么垃圾收集器会不会立即将这个对象的空间释放呢?答案是否定的,
垃圾收集器只有在当堆空间占用到了一定程度时,或者程序比较空闲时才释放那些不再使用
(遗漏)的对象空间。如果此时程序堆空间的使用不是很大,而程序又比较忙的话,则垃圾
收集器就不会运行。当然程序员也可以通过在程序中调用JDK接口来申请虚拟机主动执行垃
圾收集器。而垃圾收集器的工作和C/C++语言中明确的释放(delete)对象比起来有一个潜
在的缺点,那就是,在垃圾收集的Java应用中程序员对于安排CPU时间进行内存回收缺乏
控制,想要精确地预测出何时(甚至是否)进行垃圾收集、收集需要多长时间,基本上是不
可能的。在早期的垃圾收集策略中,对象引用计数收集算法是最先被采用的,堆中的每个对
象都有一个引用计数,当这个对象被赋值给一个变量,则该引用计数器加1,当一个对象超
过了生命期或者被重新赋值的话,对象的引用减一,任何引用计数为0的对象都可以被当作
垃圾收集。这样的算法一个固有的缺陷就是无法处理循环应用的情况,而且计数的增减也会
带来开销。现代的Java虚拟机的实现中采用了压缩收集算法、拷贝收集算法、按代收集算
法等,按代收集的算法是为了解决GC在回收对象空间的优先顺序的问题,在按代收集的算
法中,GC总是优先回收那些短暂年幼的对象,而非一些寿命较长的对象。JVM堆被划分成
剩余12页未读,继续阅读
资源评论
shangjg3
- 粉丝: 1039
- 资源: 101
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- Flume进阶-自定义拦截器jar包
- Dubins曲线算法讲解和在运动规划中的使用.pdf
- 上市公司-股票性质数据-工具变量(民企、国企、央企)2003-2022年.dta
- 上市公司-股票性质数据-工具变量(民企、国企、央企)2003-2022年.xlsx
- Reeds+Shepp曲线算法讲解和实现.pdf
- 毕业设计基于SpringBoot+MyBatisPlus+MySQL+Vue的外卖配送信息系统源代码+数据库
- 词向量(Word Embeddings)是自然语言处理(NLP)领域的一种重要技术.txt
- Surfer,线性函数
- MyBatis 的动态 SQL 是其核心特性之一.txt
- 时代的sdddsddsddsd
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功