`
ericFang
  • 浏览: 101538 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

JAVA虚拟机运行时分析

    博客分类:
  • J2SE
阅读更多
首先让我们来看看所谓的Java虚拟机在运行起来后是什么样子的,从外面来看一个Java虚拟机的运行实例就是一个运行着的Java进程,Java进程在启动过程中做了如下工作,一、根据环境变量的设置或者Java进程的命令行参数将Java Class字节码加载到内存中,这样的Java字节码是Java虚拟机所能够识别的虚拟机指令的集合,Java虚拟机在解释执行字节指令的同时,根据某些代码的使用频率,将其中一部分字节码翻译成机器能够识别的二进制指令保存在内存中,在以后对这部分代码的调用,则由Java虚拟机的代码控制CPU直接执行内存中的这部分二进制指令,这个就是Java虚拟机的热点编译技术。而在早期的Java虚拟机实现中是采用全部字节程序解释执行的方式,后来发展了Java静态编译技术,这种技术是在Java程序编译成字节码后,由一个本地编译器将这些字节码编译成二进制可执行文件,这种编译技术不利于程序的移植。再后来发展的Java的动态编译技术,这时的编译过程是在Java装载字节码文件时进行的,而此时的问题是Java在启动时需要花费很长的时间来编译这些字节码。直到最后流行的Hotspot技术的出现,此时编译仅仅运行于少部分代码。按照80/20的原则,程序的百分之80的时间仅仅运行其百分之20的代码,这样一个能够平衡启动时间、移植性的中间方法解决了人们的大部分问题。
分享到:
评论
12 楼 ericFang 2010-09-07  
1、堆(Heap)
JVM管理的内存叫堆。在32Bit操作系统上有1.5G-2G的限制,而64Bit的就没有。
JVM初始分配的内存由-Xms指定,默认是物理内存的1/64但小于1G。
JVM最大分配的内存由-Xmx指定,默认是物理内存的1/4但小于1G。
默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制,可以由-XX:MinHeapFreeRatio=指定。
默认空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制,可以由-XX:MaxHeapFreeRatio=指定。
服务器一般设置-Xms、-Xmx相等以避免在每次GC 后调整堆的大小,所以上面的两个参数没啥用。 
2.基本收集算法
复制:将堆内分成两个相同空间,从根(ThreadLocal的对象,静态对象)开始访问每一个关联的活跃对象,将空间A的活跃对象全部复制到空间B,然后一次性回收整个空间A。
因为只访问活跃对象,将所有活动对象复制走之后就清空整个空间,不用去访问死对象,所以遍历空间的成本较小,但需要巨大的复制成本和较多的内存。
标记清除(mark-sweep):收集器先从根开始访问所有活跃对象,标记为活跃对象。然后再遍历一次整个内存区域,把所有没有标记活跃的对象进行回收处理。该算法遍历整个
空间的成本较大暂停时间随空间大小线性增大,而且整理后堆里的碎片很多。
标记整理(mark-sweep-compact):综合了上述两者的做法和优点,先标记活跃对象,然后将其合并成较大的内存块。
    可见,没有免费的午餐,无论采用复制还是标记清除算法,自动的东西都要付出很大的性能代价。
11 楼 ericFang 2010-06-26  
jconsole
从1.5开始, JDK开始提供JVM监控工具Jconsole,以可视化方式对JVM的内存分配,线程数量,类数量等提供数据监视,还可以通过MBean对JVM进行控制。支持本地监控或者远程监控,使用方便,尤其在进行内存分析的时候特别有用
java -Dcom.sun.management.jmxremote.port=19819 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -jar ../demo/jfc/notepad/Notepad.jar
10 楼 ericFang 2010-06-26  
4.3 Java线程调优参数的使用
-XX:-UseBoundThreads //如果你的系统是Solaris8以上,尽情使用这个参数吧,操作
//系统内核的线程调度总是要必应用层的调度快一些
-XX:-UseLWPSynchronization //这个参数也是同样的,让操作系统来做线程同步这些工作
-XX:+UseThreadPriorities //是否采用操作系统内部定义的线程优先级
-XX:CompileThreshold=10000 //如果你想让你的系统更早变快一些,而且你的内存足够多
//的话,可以将这个参数值调小
-XX:PreBlockSpin=10 //仅仅用于Linux版本
-XX:ThreadStackSize=512 //设置线程栈的大小,如果你的应用中有比较大的循环或递
//归时使用。
-XX:+UseTLAB //是否在线程的栈空间内分配对象,如果你的内存较大的话,
//并且配置了比较大的线程栈空间,则使用这个参数会使得
//临时&本地对象的申请和释放比较快。
9 楼 ericFang 2010-06-26  
4.2 JIT调优参数的使用
从解释执行到即时编译,再到热点编译JVM走在一条不断优化的道路上,今天我们通过一些简单的参数设置就可以获得以前梦想的性能,对于Java用户来说,这的确是一条捷径:
-server //很多Hotspot的能力都是通过这个选项打开的,对于大型服
//务器尤为重要,这里可以启动热点编译功能
-Xmaxjitcodesize32m //设置即时编译代码的最大尺寸
-Xint //纯解释执行,一般情况下不用它
-Xtime //不太清楚如何使用,总之是指定JIT的时间
-XX:+DisableExplicitGC //是否屏蔽应用层的垃圾收集请求
-XX:-UseISM //使用大内存页模式则会减少GC的时间
-XX:-UseMPSS //在使用ISM选项的同时不使用该选项,否则ISM无效
8 楼 ericFang 2010-06-26  
4.1 GC调优参数的使用
JVM中按代收集算法的基本原则是这样的,JVM堆空间被分成许多子堆,每个子堆用于存放不同代的对象,而当所有已经存在的堆中的各代对象都不能继续回收时,则新的子堆会被分配,用于存放新一代的对象,下面的这两个参数就是为按代收集设计的:
-XX:NewRatio=2 //新生代于老一代的空间比率
-XX:NewSize=2228224 //缺省时2K,对于应用服务器系统建议调整的大一些4K或8K
-XX:MaxNewSize //新生代的最大空间
-XX:MaxPermSize=64m //老一代的最大空间,缺省为64M,建议增加
-XX:SurvivorRatio //GC时代子堆中的年老对象的比率
-Xxincgc //是否在垃圾收集时启用火车算法
-XX:+UseConcMarkSweepGC //是否启用并发收集算法
-Xverifyheap //仅仅用于Debug版本,用于对GC数据分析
-XX:TargetSurvivorRatio=50 //GC收集后期望得到的被老一代占用的空间,建议不调整

因为垃圾收集只是在各代的子堆满了的时候发生,总的堆的空间状况也会对垃圾收集产生重要的影响,JVM向操作系统申请更多的堆内存空间的前提是,堆中所有的年老的代的子堆都已经满了。
-Xms //设置最小初始堆空间的大小
-Xmx //设置最大堆空间的大小
-XX:MinFreeHeapRatio=40 //GC后JVM堆空间向操作系统缩小的比率。
-XX:MaxHeapFreeRatio=70 //GC后JVM堆空间向操作系统扩张的比率。
-XX:+AggressiveHeap //用于JVM运行于大内存模式下,JVM的堆空间至少在1G以
//上,与-Xms、-Xmx不同时使用,慎用!会导致JVM极度消
//耗内存
在U-NICA这样的后台大型应用服务器系统来说,我们就采用了通过调整初始堆内存空间、堆增长量、增加新生代空间配置、使用并发收集算法、火车算法等方法来使的系统的垃圾收集能力得以优化。而且在具体实际测试过程中也发现这些调整通常是有效而且成本低廉的。
7 楼 ericFang 2010-06-26  
Java内部的线程同步管理或线程调度是通过一种监视器的技术来实现的,基本上的原理如下,我们将监视器比喻成一座建筑,而其中一些特别的房间里面的数据在同一时间只能有一个“人”
——线程能够访问,当一个线程进入这个房间到它离开之前,它可以独占的操作其中的数据,我们将线程进入这个建筑叫做“进入监视器”,线程进入这个特殊的房间叫做“获得监视器”,离开房间时叫“释放监视器”,离开建筑时叫做“退出监视器”。监视器除了监控一些数据之外,还可以监控一些代码,这样的代码叫做监视区域,在同一监视器中,一块监视区域的代码在同一时间只能够被一个线程所访问。同步数据(类)或同步代码在Java程序中用Synchronized参数标明就可以了,从Java字节码编译器生成的虚拟机指令序列来看,编译器将操作指令monitorenter、monitorexit添加到具有Synchronized关键字的方法开始和结尾,而所有对具有Synchronized关键字的类数据的操作前后也都添加了monitorenter、monitorexit操作指令,这样在虚拟机指令序列(类文件代码)时JVM会调用monitorenter、monitorexit指令完成线程间的同步控制。
6 楼 ericFang 2010-06-26  
可以在编程语言级支持多线程是Java语言的一大优势,这种支持主要集中在同步上。对于编译型语言C/C++来说,在语言级是没有多线程的概念的,程序员只能通过调用操作系统API来实现多线程应用。而在Java中线程的支持是通过一些预先定义好的关键字来实现,而且JDK开发包也为用户提供了线程创建、使用的很好的封装,程序员仅仅想使用普通的类一样继承一个特定的接口Runable或者继承一个已有的简单线程类Thread即可创建并使用Java的线程功能了。应用级线程一旦创建后,就交给了JVM管理,JVM内部维护这所有应用级以及JVM内部线程列表,用户可以通过指定JVM启动的参数来设置JVM的线程管理方式,是由JVM自己管理内部线程、完成线程通过工作,还是将应用线程直接绑到操作系统内核线程,并且由操作系统内核来完成线程同步等管理工作。下面会对这些参数一一进行介绍。
5 楼 ericFang 2010-06-26  
在早期的垃圾收集策略中,对象引用计数收集算法是最先被采用的,堆中的每个对象都有一个引用计数,当这个对象被赋值给一个变量,则该引用计数器加1,当一个对象超过了生命期或者被重新赋值的话,对象的引用减一,任何引用计数为0的对象都可以被当作垃圾收集。这样的算法一个固有的缺陷就是无法处理循环应用的情况,而且计数的增减也会带来开销。现代的Java虚拟机的实现中采用了压缩收集算法、拷贝收集算法、按代收集算法等,按代收集的算法是为了解决GC在回收对象空间的优先顺序的问题,在按代收集的算法中,GC总是优先回收那些短暂年幼的对象,而非一些寿命较长的对象。JVM堆被划分成多个小的区域——子堆,每个子堆分别为不同“代”的对象服务,如果一个年幼的对象经历过好几次垃圾收集后都没有别收集掉,则它就变成一个年老的对象,会被转移到另一个存放寿命更长的对象的堆中。一切的改进就是本着让垃圾收集更快、更高效的目标进行的。在Java的语法里面,一个对象可以拥有终结方法,该方法是在垃圾收集器释放对象前必须执行的,程序员可以通过使用该方法来实现一些应用级清扫工作。
4 楼 ericFang 2010-06-26  
垃圾收集和线程同步
Java的垃圾收集器就像一个兢兢业业的仓库保管员,他管理着虚拟机堆空间的清扫工作,接着上面描述的,一旦一个函数退出了它的栈,在该函数内声明的一个Java对象则会留在Java堆空间内,那么垃圾收集器会不会立即将这个对象的空间释放呢?答案是否定的,垃圾收集器只有在当堆空间占用到了一定程度时,或者程序比较空闲时才释放那些不再使用(遗漏)的对象空间。如果此时程序堆空间的使用不是很大,而程序又比较忙的话,则垃圾收集器就不会运行。当然程序员也可以通过在程序中调用JDK接口来申请虚拟机主动执行垃圾收集器。而垃圾收集器的工作和C/C++语言中明确的释放(delete)对象比起来有一个潜在的缺点,那就是,在垃圾收集的Java应用中程序员对于安排CPU时间进行内存回收缺乏控制,想要精确地预测出何时(甚至是否)进行垃圾收集、收集需要多长时间,基本上是不可能的。
3 楼 ericFang 2010-06-26  
Java虚拟机在启动时会根据-Xms的参数值向操作系统一次性申请一块内存空间作为自己的堆,而随着后续程序的运行中内存需求的增加,则再向操作系统申请更多的内存加到自己的堆空间中。这个堆空间的最大值就是由-Xms指定的。一旦Java虚拟机发现应用程序申请的内存超过了堆内存的最大空间的话,Java就会抛出一个超出堆空间的异常。而当虚拟机在启动时如果申请不到足够的内存的话,则同样会抛出一个异常,启动失败。所有这些工作都是由Java虚拟机的内存管理模块来完成的,而Java的内存管理功能中最俱特色和重要的垃圾收集功能GC则是按照下面机制运行的。
2 楼 ericFang 2010-06-26  
Java虚拟机在运行时,由主线程开始解释执行类文件中的指令,主线程在自己的线程栈中存放临时变量、参数变量等,一旦碰到生成新对象的new操作时,就会在堆空间内申请一块内存存放该类对象,而一旦程序从一个方法中退出后(退回到一个方法栈的栈底),虚拟机程序并不会立即释放Heap空间内的这块内存,这就是与C/C++程序所不同的地方,因为C/C++程序被加载程序的操作系统调用装载到内存中之后,程序的内存是由操作系统为之分配的4G的虚拟内存空间,而堆空间的使用也是由程序的内存分配子系统(malloc)来完成的,而这个子系统仅仅是向程序员提供了申请/释放内存的调用接口,查看C/C++编译器生成的汇编代码你会发现,如果你在一个函数中申请了一块内存,而没有在函数退出的地方没有释放的话,这块内存则会永远放在堆中,而对于你在函数中生明的类变量对象来说(非new来申请的指针对象),这个类对象的内存是在程序栈空间中分配的,一旦这个函数释放则对象空间自动释放,这样的内存泄漏正是Java竭力避免的,Java从发明之初就是考虑着如何将大部分应用程序员从繁重的内存管理工作中解脱出来,而由Java虚拟机使用称之为GC垃圾收集的模块来完成内存空间的管理。
1 楼 ericFang 2010-06-26  
之后,让我们看看Java虚拟机的内部体系结构,从下面的体系机构图来看,Java的Class字节码文件经由类加载子系统加载到内存中时,虚拟机根据文件内容将类的方法和数据加载到称为方法区的地方,堆是用来为运行时类实例提供存放场所的地方,这样的堆也称之为对象堆空间。而Java栈和PC计数器则是为了Java线程而设计的,每一个Java线程一旦创建,它都将得到一个属于他自己的PC计数器(程序计数器指针,类似于CPU中的IP指令指针计数器)以及一个线程栈,在新版本Java Hotspot VM中是没有本地方法栈和线程栈之分的,只有一个线程栈的模块。这样每个线程的运行都是在属于自己栈空间内的,而所有的线程则共享着一个堆空间。当然在线程实现上不同的Java虚拟机的内部实现可能各有不同,有的自是直接将Java线程和操作系统内核线程绑定起来的,在虚拟机进程内部创建一个Java线程虚拟机就会请求操作系统为该一个进程创建一个内核线程,将线程之间的调度交给了操作系统内核来完成。而在早期的Java虚拟机一些实现中,Java线程对于操作系统来说是不可见,而是由应用层来完成线程调度,对于操作系统来说仅仅是一个单线程的进程。

相关推荐

    java虚拟机运行时数据区分析

    Java虚拟机运行时数据区分析 Java虚拟机(JVM)是一种抽象的计算机,它提供了一个运行Java字节码的环境。JVM将Java源代码编译为字节码,并在运行时执行这些字节码。为了更好地理解JVM的工作原理,我们需要了解JVM的...

    Java虚拟机规范.Java SE 8版.zip

    第2章概述Java虚拟机的整体架构,包括class文件格式、数据类型、原始类型、引用类型、运行时数据区、栈帧、浮点算法、异常等,这对理解本书后面的内容有重要帮助;第3章详述如何将Java语言编写的程序转换为Java...

    Java虚拟机实现原理分析.pdf

    Java虚拟机(JVM)是实现Java程序跨平台运行的关键技术,它的实现原理和工作过程是Java语言能够运行在各种不同硬件平台的基础。JVM的存在使得Java程序员可以编写一次代码,到处运行,这得益于JVM提供的一套平台无关...

    Java虚拟机规范中文版(JavaSE7).pdf

    类加载是Java虚拟机启动时或运行时动态加载类的过程。它由类加载器系统执行,通常分为引导类加载器、扩展类加载器和应用程序类加载器。加载过程包括加载、验证、准备、解析和初始化五个阶段,确保加载的类符合规范且...

    Java虚拟机规范 JavaSE7

    Java虚拟机(JVM)是Java程序运行的基础,它负责执行Java字节码,提供了一个与平台无关的执行环境。JVM规范定义了JVM的结构、指令集和运行时数据区,以及如何执行指令和处理异常。自1999年以来,JVM规范经历了多次...

    Java虚拟机的分析与研究.pdf

    标题:Java虚拟机的分析与研究.pdf 描述:该文件是一篇关于Java虚拟机分析与研究的...通过深入了解和分析Java虚拟机,开发者可以更有效地编写可在不同环境下运行的程序,并优化资源使用,提高软件的整体质量和安全性。

    Java零基础学习资料-Java(JVM)虚拟机运行机制

    ### Java虚拟机(JVM)运行机制详解 #### 一、解释型语言与编译型语言的区别及联系 ...其中,类加载过程是理解Java虚拟机运行机制的关键所在。掌握这些基础知识有助于开发者更好地理解和运用Java语言。

    java虚拟机各种版本

    Java虚拟机(JVM)是Java编程语言的核心组成部分,它为Java程序提供了跨平台的运行环境。Java程序在编写完成后,会被编译成字节码(.class文件),这些字节码可以在任何装有JVM的系统上运行,实现了“一次编写,到处...

    Java虚拟机规范.Java SE 8版

    第2章概述Java虚拟机的整体架构,包括class文件格式、数据类型、原始类型、引用类型、运行时数据区、栈帧、浮点算法、异常等,这对理解本书后面的内容有重要帮助;第3章详述如何将Java语言编写的程序转换为Java...

    Java虚拟机规范(中文版).pdf

    自1999年《Java虚拟机规范(第二版)》发布以来,尽管JDK在版本5时进行了重大更新,但直到2011年7月,《Java虚拟机规范(JavaSE7版)》才正式发布。这标志着JVM技术的持续演进和标准化进程的重要里程碑。随着时间...

    java虚拟机

    Java虚拟机(JVM,Java Virtual Machine)是Java平台的核心组成部分,它负责执行Java程序,为Java代码提供了跨平台的运行环境。Java虚拟机的概念始于Sun Microsystems,现在由Oracle公司继续发展和维护。JVM的设计...

    Java运行原理与Java虚拟机.pdf

    ### Java运行原理与Java虚拟机 #### 一、Java运行原理概述 Java作为一种跨平台的编程语言,其独特之处在于它的编译和解释过程。Java程序的执行涉及到两个主要步骤:首先是编译阶段,其次是解释执行阶段。 1. **...

    java虚拟机常用命令

    在Java虚拟机运行过程中,我们可能需要使用各种命令工具来监控和诊断可能出现的问题。以下是一些常用的JVM命令工具及其知识点。 1. jps命令 jps(JVM Process Status Tool)命令用于列出正在运行的Java虚拟机进程...

    java 虚拟机的研究

    Java虚拟机(Java Virtual Machine,简称JVM)作为一种跨平台的运行环境,使得Java程序能够在多种操作系统上运行。本文基于对Kaffe虚拟机的研究,介绍了一个使用C语言开发的针对Windows平台的Java虚拟机实现。该文...

    Java虚拟机规范(Java SE 7)中文版

    第2章概览了Java虚拟机整体架构,包括class文件格式、数据类型、原始类型、引用类型、运行时数据区、栈帧、浮点算法、异常等,这对理解本书后面的内容有重要帮助。第3章详述如何将Java语言编写的程序转换为Java...

    Java虚拟机规范(SE 7中文版)

    《Java虚拟机规范(JavaSE7版)》是程序员深入了解Java语言运行机制不可或缺的文档。它不是特定虚拟机实现的说明书,而是一份确保不同公司实现的Java虚拟机具有一致外部接口的契约文档。这份文档是Java程序员的基础...

    实战JAVA虚拟机

    《实战Java虚拟机——JVM故障诊断与性能优化》将通过200余示例详细介绍Java虚拟机中的各种参数配置、故障排查、性能监控以及性能优化。, 《实战Java虚拟机——JVM故障诊断与性能优化》共11章。第1~3章介绍了Java...

Global site tag (gtag.js) - Google Analytics