`
ydcworld
  • 浏览: 23581 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

jvm学习笔记--基本结构

    博客分类:
  • java
阅读更多
  主要来学习jvm的基本结构

  知识点1:什么是java虚拟机(你以为你知道,如果你看我下面的例子,你会发现你其实不知道)
第一步:先来写一个类:

package test;  
  
public class JVMTestForJava {  
    public static void main(String[] args) throws InterruptedException {  
        Thread.sleep(10000000);  
}  
}  


  第二步:cmd窗口输入:java test.JVMTestForJava
  第三步:打开任务管理器-进程

  你看到一个叫java.exe的程序没有,是滴这个就是java的虚拟机,java xxx这个命令就是用来启动一个java虚拟机,而main函数就是一个java应用的入口,main函数被执行时,java虚拟机就启动了。好了ctrl+c结束你的jvm。
  第四步:打开你的ecplise,右键run application,再run application一次
  第五步:打开任务管理器-进程

好了,我已经圈出来了,有两个javaw.exe,为什么会有两个?因为我们刚才运行了两次run application。这里我是要告诉你,一个java的application对应了一个java.exe/javaw.exe(java.exe和javaw.exe你可以把它看成java的虚拟机,一个有窗口界面一个没有)。你运行几个application就有几个java.exe/javaw.exe。或者更加具体的说,你运行了几个main函数就启动了几个java应用,同时也启动了几个java的虚拟机。
知识点1总结:
    什么是java虚拟机,什么是java的虚拟机实例?java的虚拟机相当于我们的一个java类,而java虚拟机实例,相当我们new一个java类,不过java虚拟机不是通过new这个关键字而是通过java.exe或者javaw.exe来启动一个虚拟机实例。

知识点2:jvm的生命周期
   基本上学习一种容器(更具体的说我们在学习servlet的时候),我们都要学习它的生命周期。那么jvm的生命周期如何,我一惯不喜欢丢概念,所以来实验,实践出真知,老师说过的,对不!
第一步:copy我代码

package test;  
  
public class JVMTestLife {  
    public static void main(String[] args) {  
        new Thread(new Runnable() {  
            @Override  
            public void run() {  
                for(int i=0;i<5;i++){  
                    try {  
                        Thread.currentThread().sleep(i*10000);  
                        System.out.println("睡了"+i*10+"秒");  
                    } catch (InterruptedException e) {  
                        System.out.println("干嘛吵醒我");  
                    }  
                }  
            }  
        }).start();   
          
        for(int i=0;i<50;i++){  
                System.out.print(i);  
        }  
    }  
}  


第二步:ecplise里run application
第三步:打开任务管理器-进程,看到一个javaw.exe的虚拟机在跑
第四步:查看控制台输出,并观察任务管理器中的javaw.exe什么时候消失
[java] view plaincopy
0 睡了0秒 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 睡了10秒 
睡了20秒 
睡了30秒 
睡了40秒 
这是我ecplise里的输出结果,而如果你观察控制台和任务管理器的javaw.exe会发现,当main函数的for循环打印完的时候,程序居然没有退出,而等到整个new Thread()里的匿名类的run方法执行结束后,javaw.exe才退出。我们知道在c++的win32编程(CreatThread()),main函数执行完了,寄宿线程也跟着退出了,在c#中如果你用线程池(ThreadPool)的话,结论也是如此,线程都跟着宿主进程的结束而结束。但是在java中貌似和我们的认知有很大的出入,这是为什么呢?
  这是由于java的虚拟机种有两种线程,一种叫叫守护线程,一种叫非守护线程,main函数就是个非守护线程,虚拟机的gc就是一个守护线程。java的虚拟机中,只要有任何非守护线程还没有结束,java虚拟机的实例都不会退出,所以即使main函数这个非守护线程退出,但是由于在main函数中启动的匿名线程也是非守护线程,它还没有结束,所以jvm没办法退出(有没有想干坏事的感觉??)。
  知识点2总结:java虚拟机的生命周期,当一个java应用main函数启动时虚拟机也同时被启动,而只有当在虚拟机实例中的所有非守护进程都结束时,java虚拟机实例才结束生命。

  知识点三:java虚拟机的体系结构(无奈,我怀着悲痛心情告诉你,我们必须来一些概念,别急,咱有图)
看到这个图没,名词不是普通滴多,先来看看哪些名词我们之前是说过的,执行引擎(笔记一),类装载器(笔记二),java栈(笔记十一)。
在了解jvm的结构之前,我们有必要先来了解一下操作系统的内存基本结构,这段可不能跳过,它会有助于消化上面的那个图哦!好先来看图
操作系统内存布局:

那么jvm在操作系统中如何表示的呢?
操作系统中的jvm

为什么jvm的内存是分布在操作系统的堆中呢??因为操作系统的栈是操作系统管理的,它随时会被回收,所以如果jvm放在栈中,那java的一个null对象就很难确定会被谁回收了,那gc的存在就一点意义都莫有了,而要对栈做到自动释放也是jvm需要考虑的,所以放在堆中就最合适不过了。
操作系统+jvm的内存简单布局


从上图中,你有没有发现什么规律,jvm的内存结构居然和操作系统的结构惊人的一致,你能不能给他们对号入座?还不能,没关系,再来看一个图,我帮你对号入座。看我下面红色的标注

                     从这个图,你应该不难发现,原来jvm的设计的模型其实就是操作系统的模型,基于操作系统的角度,jvm就是个该死的java.exe/javaw.exe,也就是一个应用,而基于class文件来说,jvm就是个操作系统,而jvm的方法区,也就相当于操作系统的硬盘区,所以你知道我为什么喜欢叫他permanent区吗,因为这个单词是永久的意思,也就是永久区,我们的磁盘就是不断电的永久区嘛,是一样的意思啊,多好对应啊。而java栈和操作系统栈是一致的,无论是生长方向还是管理的方式,至于堆嘛,虽然概念上一致目标也一致,分配内存的方式也一直(new,或者malloc等等),但是由于他们的管理方式不同,jvm是gc回收,而操作系统是程序员手动释放,所以在算法上有很多的差异,gc的回收算法,估计是jvm里面的经典啊,后面我们也会一点点的学习的,不要着急。
                     有没有突然自信的感觉?如果你对我的文章有自信,我们再继续,还是以图解的方式,我还是那一句,对于概念我绝对有信心让它在你脑子里根深蒂固。
                     看下面的图。

                        将这个图和上面的图对比多了什么?没错,多了一个pc寄存器,我为什么要画出来,主要是要告诉你,所谓pc寄存器,无论是在虚拟机中还是在我们虚拟机所寄宿的操作系统中功能目的是一致的,计算机上的pc寄存器是计算机上的硬件,本来就是属于计算机,(这一点对于学过汇编的同学应该很容易理解,有很多的寄存器eax,esp之类的32位寄存器,jvm里的寄存器就相当于汇编里的esp寄存器),计算机用pc寄存器来存放“伪指令”或地址,而相对于虚拟机,pc寄存器它表现为一块内存(一个字长,虚拟机要求字长最小为32位),虚拟机的pc寄存器的功能也是存放伪指令,更确切的说存放的是将要执行指令的地址,它甚至可以是操作系统指令的本地地址,当虚拟机正在执行的方法是一个本地方法的时候,jvm的pc寄存器存储的值是undefined,所以你现在应该很明确的知道,虚拟机的pc寄存器是用于存放下一条将要执行的指令的地址(字节码流)。
                        再对上面的图扩展,这一次,我们会稍微的深入一点,放心啦,不会很深入,我们的目标是浅显易懂,好学易记嘛!看下面的图。
      
多了什么?没错多了一个classLoader,其实这个图是要告诉你,当一个classLoder启动的时候,classLoader的生存地点在jvm中的堆,然后它会去主机硬盘上将A.class装载到jvm的方法区,方法区中的这个字节文件会被虚拟机拿来new A字节码(),然后在堆内存生成了一个A字节码的对象,然后A字节码这个内存文件有两个引用一个指向A的class对象,一个指向加载自己的classLoader,如下图。

那么方法区中的字节码内存块,除了记录一个class自己的class对象引用和一个加载自己的ClassLoader引用之外,还记录了什么信息呢??我们还是看图,然后我会讲给你听,听过一遍之后一辈子都不会忘记。


你仔细将这个字节码和我们的类对应,是不是和一个基本的java类惊人的一致?下面你看我贴出的一个类的基本结构。
package test;import java.io.Serializable;public final class ClassStruct extends Object implements Serializable {//1.类信息  
 //2.对象字段信息  
 private String name;  
 private int id;  
   
 //4.常量池  
 public final int CONST_INT=0;  
    public final String CONST_STR="CONST_STR";  
      
    //5.类变量区  
    public static String static_str="static_str";  
      
   
 //3.方法信息  
 public static final String getStatic_str ()throws Exception{  
  return ClassStruct.static_str;  
 }}

你将上面的代码注解和上面的那个字节码码内存块按标号对应一下,有没有发现,其实内存的字节码块就是完整的把你整个类装到了内存而已。
所以各个信息段记录的信息可以从我们的类结构中得到,不需要你硬背,你认真的看过我下面的描述一遍估计就不可能会忘记了:
       1.类信息:修饰符(public final)
                        是类还是接口(class,interface)
                        类的全限定名(Test/ClassStruct.class)
                        直接父类的全限定名(java/lang/Object.class)
                        直接父接口的权限定名数组(java/io/Serializable)
      也就是 public final class ClassStruct extends Object implements Serializable这段描述的信息提取
       2.字段信息:修饰符(pirvate)
                            字段类型(java/lang/String.class)
                            字段名(name)
        也就是类似private String name;这段描述信息的提取
       3.方法信息:修饰符(public static final)
                          方法返回值(java/lang/String.class)
                          方法名(getStatic_str)
                          参数需要用到的局部变量的大小还有操作数栈大小(操作数栈我们后面会讲)
                          方法体的字节码(就是花括号里的内容)
                          异常表(throws Exception)
       也就是对方法public static final String getStatic_str ()throws Exception的字节码的提取
       4.常量池:
                    4.1.直接常量:
                                   1.1CONSTANT_INGETER_INFO整型直接常量池public final int CONST_INT=0;
                                   1.2CONSTANT_String_info字符串直接常量池   public final String CONST_STR="CONST_STR";
                                   1.3CONSTANT_DOUBLE_INFO浮点型直接常量池
                                   等等各种基本数据类型基础常量池(待会我们会反编译一个类,来查看它的常量池等。)
                     4.2.方法名、方法描述符、类名、字段名,字段描述符的符号引用
            也就是所以编译器能够被确定,能够被快速查找的内容都存放在这里,它像数组一样通过索引访问,就是专门用来做查找的。
            编译时就能确定数值的常量类型都会复制它的所有常量到自己的常量池中,或者嵌入到它的字节码流中。作为常量池或者字节码流的一部分,编译时常量保存在方法区中,就和一般的类变量一样。但是当一般的类变量作为他们的类型的一部分数据而保存的时候,编译时常量作为使用它们的类型的一部分而保存
      5.类变量:
                  就是静态字段( public static String static_str="static_str";)
                  虚拟机在使用某个类之前,必须在方法区为这些类变量分配空间。
      6.一个到classLoader的引用,通过this.getClass().getClassLoader()来取得为什么要先经过class呢?思考一下,然后看第七点的解释,再回来思考
      7.一个到class对象的引用,这个对象存储了所有这个字节码内存块的相关信息。所以你能够看到的区域,比如:类信息,你可以通过this.getClass().getName()取得
          所有的方法信息,可以通过this.getClass().getDeclaredMethods(),字段信息可以通过this.getClass().getDeclaredFields(),等等,所以在字节码中你想得到的,调用的,通过class这个引用基本都能够帮你完成。因为他就是字节码在内存块在堆中的一个对象
      8.方法表,如果学习c++的人应该都知道c++的对象内存模型有一个叫虚表的东西,java本来的名字就叫c++- -,它的方法表其实说白了就是c++的虚表,它的内容就是这个类的所有实例可能被调用的所有实例方法的直接引用。也是为了动态绑定的快速定位而做的一个类似缓存的查找表,它以数组的形式存在于内存中。不过这个表不是必须存在的,取决于虚拟机的设计者,以及运行虚拟机的机器是否有足够的内存
--------------------------------------------------------------------------------------忽略下面虚线间的废话-------------------------------------------------------------------------------------------------------------------------
大哭好了,还剩这么多没讲过。不过不要急,我一向提倡,学到哪里讲到哪里,看到哪里。所以没有学到的概念,让他随风去。
但是我还是会来串一下思路滴:
                 首先,当一个程序启动之前,它的class会被类装载器装入方法区(不好听,其实这个区我喜欢叫做Permanent区),执行引擎读取方法区的字节码自适应解析,边解析就边运行(其中一种方式),然后pc寄存器指向了main函数所在位置,虚拟机开始为main函数在java栈中预留一个栈帧(每个方法都对应一个栈帧),然后开始跑main函数,main函数里的代码被执行引擎映射成本地操作系统里相应的实现,然后调用本地方法接口,本地方法运行的时候,操纵系统会为本地方法分配本地方法栈,用来储存一些临时变量,然后运行本地方法,调用操作系统APIi等等。

原文地址:http://blog.csdn.net/yfqnihao/article/details/8289363
分享到:
评论

相关推荐

    jVM学习笔记.ppt

    JVM的学习可以从其基本结构、代码编译和执行过程,以及内存管理和垃圾回收机制三个方面进行深入探讨。 首先,JVM的基本结构分为逻辑结构和物理结构。逻辑结构主要包括Java源码编译器、JVM执行引擎、类加载器等组件...

    java学习笔记-----给java初学者

    Java学习笔记是专门为Java初学者设计的一套详尽的学习资源,旨在帮助新手快速掌握这门广泛使用的编程语言。这份笔记涵盖了从基础概念到高级特性的全面内容,是学习和复习Java知识的理想工具。 1. **Java简介** ...

    JAVA学习笔记-java学习笔记WORD样式.docx

    ### JAVA学习笔记知识点详解 #### 一、计算机概述 1. **计算机**:电子设备,用于处理信息。 2. **计算机硬件**: - **中央处理器(CPU)**:计算机的大脑,负责处理指令。 - **内存(RAM)**:临时存储数据,...

    良葛格 Java 学习笔记-JavaGossip全(v1+v2)

    《良葛格 Java 学习笔记-JavaGossip全(v1+v2)》是一部集成了作者良葛格多年编程经验的学习资料,旨在帮助初学者和有经验的开发者深入理解和掌握Java这门强大的编程语言。这份笔记包含了JavaGossip的两个版本,v1和...

    JVM学习笔记

    ### JVM学习笔记知识点详解 #### 一、JVM的基本结构 **JVM(Java Virtual Machine,Java虚拟机)**是一种可以执行Java字节码的虚拟机。它为Java提供了平台无关性,使得Java代码可以在任何安装了JVM的平台上运行。 ...

    Java架构面试专题(含答案)和学习笔记-1

    本资料包含学习笔记和答案,便于自我检验和理解。 1. **Java基础知识**: - **内存管理**:包括垃圾回收机制、内存泄漏及其检测方法、JVM内存模型(堆、栈、方法区等)。 - **数据类型与数据结构**:深入理解原始...

    JAVA学习经典笔记-----2

    ### JAVA学习经典笔记知识点概述 #### 一、Java与C++的区别 1. **内存管理:** Java自动管理...这些知识点覆盖了Java语言的基础概念、特性、开发环境配置、语法结构等多个方面,对于初学者来说是非常宝贵的学习资料。

    Java并发编程与高并发解决方案-学习笔记-www.itmuch.com.pdf

    本文将基于文档《Java并发编程与高并发解决方案-学习笔记***.pdf》中提供的内容,来详细阐述并发编程和高并发的基本概念、CPU多级缓存与缓存一致性、以及Java内存模型。 ### 并发与高并发概念 在现代多线程编程中...

    JVM内存结构笔记.rar

    Java虚拟机(JVM)是Java程序运行的核心,它的内存结构对于理解和优化Java应用程序的性能至关重要。本笔记将深入探讨JVM内存的...这份"JVM内存结构笔记"将详细阐述这些内容,是学习和研究JVM内存管理的重要参考资料。

    jvm笔记

    今天,我们要讨论的是 JVM 的笔记,这个笔记包括了 JVM 的基本结构、类加载机制、类文件格式等内容。 首先,让我们来看一下 JVM 的基本结构。JVM 可以分为三个部分:CLASS LOADER、RUN TIME DATA AREA 和 EXECUTION...

    JVM内存管理学习笔记

    《JVM内存管理学习笔记》 在Java世界中,JVM(Java Virtual Machine)是运行所有Java应用程序的核心。深入理解JVM内存管理对于优化程序性能、预防和解决内存泄漏问题至关重要。本文将从JVM内存模型、内存区域划分、...

    java笔记--

    Java编程语言是面向对象的、跨平台...这些只是Java编程中的一部分知识点,实际的Java学习过程中,还需要深入理解反射、注解、并发编程、JVM原理、设计模式等多个方面。不断实践和学习,才能成为一名优秀的Java开发者。

    《java学习》-Java 学习笔记.zip

    本压缩包文件“《java学习》-Java 学习笔记.zip”包含了丰富的学习资源,帮助初学者和进阶者深入理解Java编程。 1. **Java基础知识** - **语法**:Java的基础语法包括变量、数据类型、运算符、流程控制语句(如if-...

    Java学习笔记及心得

    总结以上知识点,Java学习笔记及心得主要涵盖了Java的环境配置、基本语法、面向对象编程的概念和实践等方面的内容。这些知识是Java编程入门和进一步学习的基础,为深入学习Java语言和理解其面向对象的特性提供了扎实...

    Java,JVM相关笔记的代码知识

    这份JVM相关的笔记包含了深入理解JVM内部工作机制的关键代码资源,是学习和优化Java应用程序的重要参考资料。下面,我们将深入探讨Java与JVM的相关知识点。 1. **类加载机制**:JVM通过类加载器(ClassLoader)将...

    记录一些自己学习MySQL,JUC,JVM的学习笔记.zip

    MySQL是世界上最受欢迎的关系型数据库管理系统之一,用于存储和管理数据。...通过这些笔记,你可以系统地学习和理解MySQL数据库、Java并发编程以及JVM的运作机制,为你的软件开发职业生涯打下坚实的基础。

    Java学习笔记——良葛格

    "Java学习笔记——良葛格"是一份专为初学者设计的教程资料,由良葛格精心编写,旨在帮助读者掌握JDK5.0版本的Java基础知识。JDK(Java Development Kit)是Java开发的核心工具集,包含了编译器、调试器和运行环境等...

    Java基础笔记-笔试用

    以上就是Java基础笔记中可能涵盖的关键知识点,理解并熟练掌握这些概念对于Java开发者来说至关重要,特别是在面试和笔试中。深入学习和实践这些知识,将有助于提升你的编程技能和解决问题的能力。

    java学习笔记markdown

    【Java学习笔记Markdown版】是针对Java初学者和进阶者的一份详尽教程,以Markdown格式编写,便于阅读和整理。Markdown是一种轻量级的标记语言,它允许用户使用易读易写的纯文本格式编写文档,然后转换成结构化的HTML...

Global site tag (gtag.js) - Google Analytics