`
ihyperwin
  • 浏览: 434740 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

JVM研究

    博客分类:
  • JVM
 
阅读更多

1 JVM简介

JVM是我们Javaer的最基本功底了,刚开始学Java的时候,一般都是从“Hello World”开始的,然后会写个复杂点class,然后再找一些开源框架,比如SpringHibernate等等,再然后就开发企业级的应用,比如网站、企业内部应用、实时交易系统等等,直到某一天突然发现做的系统咋就这么慢呢,而且时不时还来个内存溢出什么的,今天是交易系统报了StackOverflowError,明天是网站系统报了个OutOfMemoryError,这种错误又很难重现,只有分析Javacoredump文件,运气好点还能分析出个结果,运行遭的点,就直接去庙里烧香吧!每天接客户的电话都是战战兢兢的,生怕再出什么幺蛾子了。我想Java做的久一点的都有这样的经历,那这些问题的最终根结是在哪呢?—— JVM

JVM全称是Java Virtual MachineJava虚拟机,也就是在计算机上再虚拟一个计算机,这和我们使用 VMWare不一样,那个虚拟的东西你是可以看到的,这个JVM你是看不到的,它存在内存中。我们知道计算机的基本构成是:运算器、控制器、存储器、输入和输出设备,那这个JVM也是有这成套的元素,运算器是当然是交给硬件CPU还处理了,只是为了适应一次编译,随处运行的情况,需要做一个翻译动作,于是就用了JVM自己的命令集,这与汇编的命令集有点类似,每一种汇编命令集针对一个系列的CPU,比如8086系列的汇编也是可以用在8088上的,但是就不能跑在8051上,而JVM的命令集则是可以到处运行的,因为JVM做了翻译,根据不同的CPU,翻译成不同的机器语言。

JVM中我们最需要深入理解的就是它的存储部分,存储?硬盘?NONO JVM是一个内存中的虚拟机,那它的存储就是内存了,我们写的所有类、常量、变量、方法都在内存中,这决定着我们程序运行的是否健壮、是否高效,接下来的部分就是重点介绍之。

2 JVM的组成部分

我们先把JVM这个虚拟机画出来,如下图所示:



 

 

 

从这个图中可以看到,JVM是运行在操作系统之上的,它与硬件没有直接的交互。我们再来看下JVM有哪些组成部分,如下图所示:



 

 
该图参考了网上广为流传的JVM构成图,大家看这个图,整个JVM分为四部分:

Class Loader 类加载器

类加载器的作用是加载类文件到内存,比如编写一个HelloWord.java程序,然后通过javac编译成class文件,那怎么才能加载到内存中被执行呢?Class Loader承担的就是这个责任,那不可能随便建立一个.class文件就能被加载的,Class Loader加载的class文件是有格式要求,在《JVM Specification》中式这样定义Class文件的结构:

    ClassFile {

      u4 magic;

      u2 minor_version;

      u2 major_version;

      u2 constant_pool_count;

      cp_info constant_pool[constant_pool_count-1];

      u2 access_flags;

      u2 this_class;

      u2 super_class;

      u2 interfaces_count;

      u2 interfaces[interfaces_count];

      u2 fields_count;

      field_info fields[fields_count];

      u2 methods_count;

      method_info methods[methods_count];

      u2 attributes_count;

      attribute_info attributes[attributes_count];

    }

需要详细了解的话,可以仔细阅读《JVM Specification》的第四章“The class File Format”,这里不再详细说明。

友情提示:Class Loader只管加载,只要符合文件结构就加载,至于说能不能运行,则不是它负责的,那是由Execution Engine负责的。

Execution Engine 执行引擎

执行引擎也叫做解释器(Interpreter),负责解释命令,提交操作系统执行。

Native Interface本地接口

本地接口的作用是融合不同的编程语言为Java所用,它的初衷是融合C/C++程序,Java诞生的时候是C/C++横行的时候,要想立足,必须有一个聪明的、睿智的调用C/C++程序,于是就在内存中专门开辟了一块区域处理标记为native的代码,它的具体做法是Native Method Stack中登记native方法,在Execution Engine执行时加载native libraies。目前该方法使用的是越来越少了,除非是与硬件有关的应用,比如通过Java程序驱动打印机,或者Java系统管理生产设备,在企业级应用中已经比较少见,因为现在的异构领域间的通信很发达,比如可以使用Socket通信,也可以使用Web Service等等,不多做介绍。

Runtime data area运行数据区

运行数据区是整个JVM的重点。我们所有写的程序都被加载到这里,之后才开始运行,Java生态系统如此的繁荣,得益于该区域的优良自治,下一章节详细介绍之。

 

整个JVM框架由加载器加载文件,然后执行器在内存中处理数据,需要与异构系统交互是可以通过本地接口进行,瞧,一个完整的系统诞生了!

2 JVM的内存管理

所有的数据和程序都是在运行数据区存放,它包括以下几部分:

Stack

栈也叫栈内存,是Java程序的运行区,是在线程创建时创建,它的生命期是跟随线程的生命期,线程结束栈内存也就释放,对于栈来说不存在垃圾回收问题,只要线程一结束,该栈就Over。问题出来了:栈中存的是那些数据呢?又什么是格式呢?

栈中的数据都是以栈帧(Stack Frame)的格式存在,栈帧是一个内存区块,是一个数据集,是一个有关方法(Method)和运行期数据的数据集,当一个方法A被调用时就产生了一个栈帧F1,并被压入到栈中,A方法又调用了B方法,于是产生栈帧F2也被压入栈,执行完毕后,先弹出F2栈帧,再弹出F1栈帧,遵循先进后出原则。

那栈帧中到底存在着什么数据呢?栈帧中主要保存3类数据:本地变量(Local Variables),包括输入参数和输出参数以及方法内的变量;栈操作(Operand Stack),记录出栈、入栈的操作;栈帧数据(Frame Data),包括类文件、方法等等。光说比较枯燥,我们画个图来理解一下Java栈,如下图所示:




 
图示在一个栈中有两个栈帧,栈帧2是最先被调用的方法,先入栈,然后方法2又调用了方法1,栈帧1处于栈顶的位置,栈帧2处于栈底,执行完毕后,依次弹出栈帧1和栈帧2,线程结束,栈释放。

Heap 堆内存

一个JVM实例只存在一个堆类存,堆内存的大小是可以调节的。类加载器读取了类文件后,需要把类、方法、常变量放到堆内存中,以方便执行器执行,堆内存分为三部分:

Permanent Space 永久存储区

永久存储区是一个常驻内存区域,用于存放JDK自身所携带的Class,Interface的元数据,也就是说它存储的是运行环境必须的类信息,被装载进此区域的数据是不会被垃圾回收器回收掉的,关闭JVM才会释放此区域所占用的内存。

Young Generation Space 新生区

新生区是类的诞生、成长、消亡的区域,一个类在这里产生,应用,最后被垃圾回收器收集,结束生命。新生区又分为两部分:伊甸区(Eden space)和幸存者区(Survivor pace),所有的类都是在伊甸区被new出来的。幸存区有两个: 0区(Survivor 0 space)和1区(Survivor 1 space)。当伊甸园的空间用完时,程序又需要创建对象,JVM的垃圾回收器将对伊甸园区进行垃圾回收,将伊甸园区中的不再被其他对象所引用的对象进行销毁。然后将伊甸园中的剩余对象移动到幸存0区。若幸存0区也满了,再对该区进行垃圾回收,然后移动到1区。那如果1区也满了呢?再移动到养老区。

Tenure generation space养老区

养老区用于保存从新生区筛选出来的JAVA对象,一般池对象都在这个区域活跃。   三个区的示意图如下:


 

 
Method Area 方法区

方法区是被所有线程共享,该区域保存所有字段和方法字节码,以及一些特殊方法如构造函数,接口代码也在此定义。

PC Register 程序计数器

每个线程都有一个程序计数器,就是一个指针,指向方法区中的方法字节码,由执行引擎读取下一条指令。

Native Method Stack 本地方法栈

 

 

 

3 JVM相关问题

问:堆和栈有什么区别

答:堆是存放对象的,但是对象内的临时变量是存在栈内存中,如例子中的methodVar是在运行期存放到栈中的。

栈是跟随线程的,有线程就有栈,堆是跟随JVM的,有JVM就有堆内存。

 

问:堆内存中到底存在着什么东西?

答:对象,包括对象变量以及对象方法。

 

问:类变量和实例变量有什么区别?

答:静态变量是类变量,非静态变量是实例变量,直白的说,有static修饰的变量是静态变量,没有static修饰的变量是实例变量。静态变量存在方法区中,实例变量存在堆内存中。

 

问:我听说类变量是在JVM启动时就初始化好的,和你这说的不同呀!

答:那你是道听途说,信我的,没错。

 

问:Java的方法(函数)到底是传值还是传址?

答:都不是,是以传值的方式传递地址,具体的说原生数据类型传递的值,引用类型传递的地址。对于原始数据类型,JVM的处理方法是从Method AreaHeap中拷贝到Stack,然后运行frame中的方法,运行完毕后再把变量指拷贝回去。

 

问:为什么会产生OutOfMemory产生?

答:一句话:Heap内存中没有足够的可用内存了。这句话要好好理解,不是说Heap没有内存了,是说新申请内存的对象大于Heap空闲内存,比如现在Heap还空闲1M,但是新申请的内存需要1.1M,于是就会报OutOfMemory了,可能以后的对象申请的内存都只要0.9M,于是就只出现一次OutOfMemoryGC也正常了,看起来像偶发事件,就是这么回事。       但如果此时GC没有回收就会产生挂起情况,系统不响应了。

 

问:我产生的对象不多呀,为什么还会产生OutOfMemory

答:你继承层次忒多了,Heap中 产生的对象是先产生 父类,然后才产生子类,明白不?

 

问:OutOfMemory错误分几种?

答:分两种,分别是“OutOfMemoryError:java heap size””OutOfMemoryError: PermGen space”,两种都是内存溢出,heap size是说申请不到新的内存了,这个很常见,检查应用或调整堆内存大小。

“PermGen space”是因为永久存储区满了,这个也很常见,一般在热发布的环境中出现,是因为每次发布应用系统都不重启,久而久之永久存储区中的死对象太多导致新对象无法申请内存,一般重新启动一下即可。

 

问:为什么会产生StackOverflowError

答:因为一个线程把Stack内存全部耗尽了,一般是递归函数造成的。

 

问:一个机器上可以看多个JVM吗?JVM之间可以互访吗?

答:可以多个JVM,只要机器承受得了。JVM之间是不可以互访,你不能在A-JVM中访问B-JVMHeap内存,这是不可能的。在以前老版本的JVM中,会出现A-JVM Crack后影响到B-JVM,现在版本非常少见。

 

问:为什么Java要采用垃圾回收机制,而不采用C/C++的显式内存管理?

答:为了简单,内存管理不是每个程序员都能折腾好的。

 

问:为什么你没有详细介绍垃圾回收机制?

答:垃圾回收机制每个JVM都不同,JVM Specification只是定义了要自动释放内存,也就是说它只定义了垃圾回收的抽象方法,具体怎么实现各个厂商都不同,算法各异,这东西实在没必要深入。

 

问:JVM中到底哪些区域是共享的?哪些是私有的?

答:HeapMethod Area是共享的,其他都是私有的,

 

问:什么是JIT,你怎么没说?

答:JIT是指Just In Time,有的文档把JIT作为JVM的一个部件来介绍,有的是作为执行引擎的一部分来介绍,这都能理解。Java刚诞生的时候是一个解释性语言,别嘘,即使编译成了字节码(byte code)也是针对JVM的,它需要再次翻译成原生代码(native code)才能被机器执行,于是效率的担忧就提出来了。Sun为了解决该问题提出了一套新的机制,好,你想编译成原生代码,没问题,我在JVM上提供一个工具,把字节码编译成原生码,下次你来访问的时候直接访问原生码就成了,于是JIT就诞生了,就这么回事。

 

问:JVM还有哪些部分是你没有提到的?

答:JVM是一个异常复杂的东西,写一本砖头书都不为过,还有几个要说明的:

常量池(constant pool):按照顺序存放程序中的常量,并且进行索引编号的区域。比如int i =100,这个100就放在常量池中。

安全管理器(Security Manager):提供Java运行期的安全控制,防止恶意攻击,比如指定读取文件,写入文件权限,网络访问,创建进程等等,Class LoaderSecurity Manager认证通过后才能加载class文件的。

方法索引表(Methods table),记录的是每个method的地址信息,StackHeap中的地址指针其实是指向Methods table地址。

      

问:为什么不建议在程序中显式的生命System.gc()

答:因为显式声明是做堆内存全扫描,也就是Full GC,是需要停止所有的活动的(Stop  The World Collection),你的应用能承受这个吗?

 

问:JVM有哪些调整参数?

答:非常多,自己去找,堆内存、栈内存的大小都可以定义,甚至是堆内存的三个部分、新生代的各个比例都能调整。

 

 

  • 大小: 15.6 KB
  • 大小: 28.2 KB
  • 大小: 46.9 KB
  • 大小: 34.4 KB
分享到:
评论
1 楼 pulsar_lxl 2015-05-14  
请注明转载
原文:http://hllvm.group.iteye.com/group/wiki/2905-JVM

相关推荐

    1.java基础知识回顾 2.java高级语法研究 3.jvm研究 4.如果写出优雅高兴的java代码.zip

    3. **JVM研究**:Java虚拟机是Java程序运行的核心,它的内存管理(如堆内存、栈内存、方法区)、垃圾回收机制、类加载机制、性能优化等方面都是深入学习的重点。了解JVM的工作原理有助于优化代码,避免内存泄漏,...

    嵌入式LINUX中的JVM研究

    总的来说,嵌入式Linux中的JVM研究涵盖了从低层次的处理器交互到高级的内存管理和垃圾收集策略。通过深入理解这些技术,开发者可以创建更高效、更可靠且更适合嵌入式环境的Java应用程序。这不仅涉及到代码的编写,还...

    JVM知识图谱.pdf

    - **讲师介绍**:本课程将由具有多年Java开发经验及JVM研究背景的专业讲师主讲。 #### 二、课程整体介绍 - **目标**:深入理解JVM的工作原理,掌握JIT编译器的机制及其对程序性能的影响。 - **内容**:涵盖JVM基础...

    jdk,jvm源码

    在研究JVM源码时,可以参考OpenJDK项目,它是JDK的开源实现,提供了完整的JVM源代码。通过阅读源码,我们可以学习到更多关于类加载、内存管理、线程调度等底层细节,并且能够针对具体问题进行定制化开发。 个人网站...

    jvm 启动过程 JVM 原理

    Java虚拟机(JVM)是Java程序运行的基础,它是一个抽象的计算机系统,负责执行Java字节码。本文将深入探讨JVM的启动过程...通过深入研究JVM,开发者可以更好地解决内存溢出、性能瓶颈等问题,实现更高效的Java应用。

    Dynamic Monitor Allocation in the Java Virtual Machine

    动态监测器分配的研究对JVM研究人员极具参考价值,因为它直接关系到JVM性能优化的关键部分。动态监测器分配的主要思想是,当且仅当对象需要进行线程同步时,才会为其分配monitor。这样的处理方式可以有效减少不必要...

    JVM图解-JVM指令-JVM原型图.rar

    Java虚拟机(JVM)是Java程序运行的基础,它是一个抽象的计算机系统,负责执行Java字节码。在这个压缩包中,"JVM图解.png"可能是对JVM内部结构的...通过研究这个压缩包中的资源,你可以更深入地了解这个强大的虚拟机。

    Java JVM Instruction Set

    本文档的主要目标是研究Java虚拟机(JVM)的工作原理及其设计背后的原因,而非深入探讨Java语言本身。我们将关注于机器如何运作,并且更重要的是,探究JVM开发者为何选择特定的方式来设计这些功能。 #### 为什么...

    JVM 原理及工作机制

    Java虚拟机(JVM)是Java编程语言的核心组成部分,它为Java程序提供了跨平台的运行环境。...同时,对于想要深入了解Java底层机制、开发Java工具或者研究JVM优化的人,深入研究JVM规格更是必不可少。

    monkey老师的jvm 调优

    《Monkey老师的JVM调优深度解析》 在Java开发领域,JVM(Java Virtual Machine)是每一个程序员都需要深入了解的关键组成部分。...这是一项对个人职业发展至关重要的技能,值得每一位Java开发者深入研究。

    深入理解jvm虚拟机

    标题提到的“深入理解JVM虚拟机”,意味着要对JVM的内部机制进行深入的研究和理解。其核心知识点涵盖了如下几个方面: 1. JVM架构组成:JVM主要由类加载器(Class Loader)、运行时数据区(Runtime Data Area)、...

    Binary Viewer和jclasslib bytecode viewer

    总的来说,Binary Viewer和jclasslib bytecode viewer是Java开发者和JVM研究者的得力助手,它们能够增强你对字节码的理解,从而提升你在Java编程和JVM优化方面的技能。通过实践和探索,你可以更深入地理解Java运行时...

    jvm详解资料

    ### JVM详解资料核心知识点 #### Java相关 - **Java定义**:Java是一种广泛使用的面向对象的编程语言,...JVM的复杂性和灵活性使其成为现代软件工程中不可或缺的一部分,同时也为持续学习和研究提供了丰富的领域。

    Java虚拟机分析

    性能优化是JVM研究中的另一个关键方面。提高JVM的运行效率,可以从多个方面入手,如优化类加载机制、提高执行引擎的执行效率、改进垃圾收集算法等。例如,可以采用即时编译技术(JIT)来提高解释执行的效率,或者...

    jVM学习笔记.ppt

    《深入理解JVM》 Java虚拟机(JVM)是Java平台的核心组成部分,它负责运行Java程序,并提供了内存管理、垃圾回收以及类加载等关键功能...深入研究JVM的每一个细节,能够帮助开发者更好地编写出高效、稳定的Java程序。

    JVM指令集.zip

    Java虚拟机(JVM)是Java程序运行的基础,它...综上所述,JVM指令集是Java程序员深入研究JVM、优化代码和解决运行时问题的关键工具。通过学习和掌握JVM指令集,开发者可以提升自己的专业技能,更好地驾驭Java这门语言。

    JAVA虚拟机(JVM)规范(中文版).rar

    **JAVA虚拟机(JVM)规范** JAVA虚拟机(JVM)是Java语言的核心组成部分,它为Java程序提供了运行环境,使得Java代码能在任何支持JVM的平台上...《JAVA虚拟机(JVM)规范(中文版)》这份文档将是深入研究JVM的宝贵资源。

    hsdis-amd64.dll 资源下载

    hsdis-amd64.dll 不仅适用于开发者,也是性能分析师和JVM研究者的得力工具。它可以配合其他JVM诊断工具,如VisualVM、JProfiler等,提供更深入的洞察,帮助找出性能瓶颈,并优化Java应用的性能。 在实际使用中,...

Global site tag (gtag.js) - Google Analytics