java虚拟机的三种含义:
- 抽象的规范
- 一个具体的实现
- 一个运行中的虚拟机实例

---------------------java虚拟机的生命周期:
java虚拟机实例的天职就是负责运行一个java程序。
启动一个java程序,一个虚拟机实例诞生了;程序关闭退出,虚拟机消亡。
有几个java程序正在运行,就有几个java虚拟机实例。每个java程序都运行在自己的java虚拟机实例中。

java虚拟机中有两种线程:
- 守护线程:由虚拟机自己使用的(执行垃圾收集线程),java程序也可以把任何线程标记为守护线程。
- 非守护线程:main()这种。

非守护线程都终止时,虚拟机实例才自动退出。(也可以调用Runtime或System的exit()方法退出程序)。

---------------------java虚拟机的体系结构:
见同目录第五章.Java虚拟机-体系结构图!
方法区和堆是该虚拟机实例的所有线程共享的。
当虚拟机装载一个class文件时,他会从这个class文件包含的二进制数据中解析类型信息,然后把这些类型信息放到方法区中。
当程序运行时,虚拟机会把所有该程序在运行时创建的对象都放到堆中。

每个新线程被创建时,他都将得到它自己的PC寄存器以及一个java栈(不是所有线程共享)。
java虚拟机为每个线程创建内存区,这些内存区域是私有的,任何线程都不能访问另一个线程的PC寄存器或者java栈。
如果线程正在执行的是一个java方法(非本地方法),那么PC寄存器的值将总是指示下一条将被执行的指令。
java栈则总是存储该线程中java方法调用的状态(局部变量、被调用时传进来的参数、返回值、运算的中间结果)

本地方法调用的状态则是以某种依赖于具体实现的方式存储在本地方法栈中,也可能在寄存器或者其他某些特定实现相关的内存区中。

---------------------栈帧(1):
java栈上由许多栈帧(帧)组成的,一个栈帧包含一个java方法调用的状态。
当线程调用一个java方法时,虚拟机压入一个新的栈帧到该线程的java栈中;当方法返回时,这个栈帧被从java栈中弹出并抛弃。

java虚拟机没有寄存器,其指令集使用java栈来存储中间数据(为了平台无关性)。

---------------------类型数据
类型数据分为来那个中:
基本类型:float、double、byte、short、int、long、char、boolean
引用类型:reference(类引用、接口引用、数组引用)
注意:编译成字节码时boolean用int表示,

java虚拟机中,最基本的数据单元就是字,至少选择32位作为字长。
运行时数据区的大部分内容,都是基于“字”这个抽象概念的。

---------------------类装载器子系统:
类装载器的装载、连接和初始化:
- 装载:查找并装载类型的二进制数据
- 连接:执行验证,准备,以及解析(可选)。
验证:确保被导入类型的正确性。
准备:为静态变量分配内存,并将其初始化为默认值。
解析:把类型中的符号引用转换为直接引用。
- 初始化:把静态变量初始化为正确初始值。

启动类装载器:
只要是符合java class文件格式的二进制文件,java虚拟机实现都必须能够从中辨别并装载器中的类和接口。每个java虚拟机实现必须有一个启动类加载器来加载受信任的类,比如java API。

用户自定义类装载器:
用户自定义的类装载器是普通的java对象,它的类必须派生自java.lang.ClassLoader类。ClassLoader类中定义的方法为程序提供了访问类装载器机制的接口。
用户自定义类装载器和Class类的实例都放在内存中的堆区,而装载的类型信息则都位于方法区。

ClassLoader类的四个通往java虚拟机的方法:
protected final Class defineClass(String name, byte data[], int offset, int length);
接收一个名为data[]的字节数组,并且在data[offset]到data[data+length]之间的二进制数据必须符合java class格式(表示一个新的可用类),name是该类型的全限定名,并将赋以默认的保护域。注意:该方法返回Class对象实例时表示指定的class文件已经被找到并装载到了方法区(不一定连接和初始化)

protected final Class defineClass(String name, byte data[], int offset, int length, 
ProtectionDomain protectionDomain);
与前面一样,只是,该类型的保护域将由它的protectionDomain参数指定。

protected final Class findSystemClass(String name);
接收一个字符串name(该类型的全限定名),用于启动系统类装载器(必须保证能启动)。

protected final void resolveClass(Class c);
接收一个Class实例的引用作为参数,它将对该Class实例表示的类型执行连接动作(必须保证能执行连接动作)。

---------------------方法区:
所有线程都共享方法区,所以它们对方法区数据的访问必须被设计为是线程安全的。
方法区的大小不必说固定的,虚拟机可以根据应用的需要动态调整。
方法区不必是连续的。
方法区也可以被垃圾收集。

类型信息:
对每个装载的类型,虚拟机都会在方法区中存储一下类型信息:
- 该类型全限定名
- 该类型的直接超类的全限定名(除非是Object类,没有超类)
- 该类型是类类型还是接口类型
- 该类型的访问修饰符(public、abstract、final的某个子集)
- 任何型直接超接口的全限定名的有序列表

- 该类型的常量池【核心】:所有常量的类型字段方法的符号引用(索引访问)
- 字段信息:字段名,字段类型,字段修饰符
- 方法信息:方法名,返回类型,参数数量和类型(按序),方法修饰符
- 除了常量以外的静态变量
- 一个到类ClassLoader的引用:跟踪保存该类加载时所用的加载器的类别
- 一个到Class类的引用:虚拟机会创建一个相应的java.lang.Class类的实例

---------------------方法表:
方法表:类型数据结构
虚拟机为每个非抽象类都生成一个表,把它作为类信息的一部分保存在方法区。
方法表是一个数组,元素是所有它的实例可能被调用的实例方法的直接引用
,包括是超类直接继承过来的方法。运行时可以通过方法表快速搜寻在对象中调用的实例方法。

---------------------堆:
java程序在运行时创建的所有类实例或数组都放在同一个堆中(要考虑线程同步问题)。
和方法区一样,堆空间也不是连续的内存区。

---------------------数组:
数组的内部表示:
在java中,数组才是真正的对象
和其他对象一样,数组总是存储在堆中。
和其他对象一样,数组也有一个与他们的类关联的Class实例,所有具有相同维度和类型的数组都是同一个类的实例(不管数组的长度是多少)。

数组类的名称由两部分组成,每一维度用一个"["表示,用字符或字符串表示元素类型。如“[[Ljava/lang/Object”表示元素为Object的二维数组。

在堆中,每一个数组对象还必须要保存数组的长度、数组数据以及某些指向数组的类数据的引用。

---------------------程序计数器(PC寄存器):
每一个线程都有它自己的PC寄存器,它是在该线程启动的时候创建的。
PC寄存器的大小是字长,因此能够持有一个本地指针,也能够持有一个returnAddress。当线程执行某个java方法时,PC寄存器的内容总是写一条将被执行的指令的地址,这里的地址可以是个本地指针,也可以是在方法字节码中相对于该方法其实指令的偏移量。如果该线程正在执行一个本地方法,此时PC寄存器的值是“undefined”。

---------------------Java栈:
每当启动一个新线程时,java虚拟机都会为它分配一个java栈。
虚拟机智慧直接对java栈执行两种操作:以帧为单位的压栈或出栈。
每当线程调用一个java方法时,虚拟机都会在该java栈中压入一个新帧。
java方法不管是正常返回还是抛异常中止,虚拟机都会将当前栈弹出java栈,然后释放内存。

java栈和栈帧在内存中也不必说连续的。

---------------------栈帧(2):
栈帧的构成:
- 局部变量区:
是一个以字长为单位,从0开始计数的数组。字节码指令通过从0开始的索引来使用其中的数据。
int、float、reference和returnAddress的值在数组中只占一项;
byte、short、char的值在存入数组前都被转换成int,所以也只占一项;
boolean虚拟机不支持,用int来表示,所以也只占一项;
long、double的值在数组中占两项(使用只要指出第一项索引值)。
局部变量区包含对应的方法参数和局部变量。
按参数的顺序来存入局部变量数组中。真正的局部变量顺序任意。

- 操作数栈:
是一个以字节为单位的数组(不是通过索引来访问),是通过标准的栈操作(压栈和出栈)来访问。
存储的数据类型和局部变量区的一样。
虚拟机把操作数栈作为他的工作区,大多数指令都要从这里弹出数据,执行计算,然后把结果压回到操作数栈中。

- 帧数据区:
常量池解析、正常方法返回、异常派发机制。
每当虚拟机要执行某个需要用到常量池数据的指令时,它都会通过帧数据区中指向常量池的指针来访问它。
帧数据区还要帮助虚拟机处理java方法的正常结束或异常中止:
如果正常结束:虚拟机必须恢复发起调用的方法的(上一个)栈帧,调用完成方法的指令的下一个指令。如果有返回值,虚拟机将把返回值压倒发 起调用的方法的操作数栈。
如果抛出异常,根据帧数据区的异常表来处理。如果有catch语句,就会交给catch中的代码,如果没有,则立即异常中止。

---------------------本地方法栈:
当线程调用本地方法时,虚拟机会保持java栈不变,不再在线程的java栈中压入新的帧,虚拟机只是简单地动态连接并直接调用指定的本地方法。

就像其他运行时内存区一样,本地方法栈占用的内存区也不必说固定大小的,它可以根据需要动态扩展或者收缩。

---------------------执行引擎:
任何java虚拟机实现的核心都是它的执行引擎。
在java虚拟机规范中,执行引擎的行为使用指令集来定义。
作为运行时实例的执行引擎就是一个线程。
运行中java程序的每一个线程都是一个独立的虚拟机执行引擎的实例。从生命周期的开始到结束,它要么在执行字节码,要么在执行本地方法。

本文转自天天_byconan博客园博客,原文链接:http://www.cnblogs.com/tiantianbyconan/archive/2013/02/24/2923987.html,如需转载请自行联系原作者

[看书笔记]《深入java虚拟机》——java体系结构(二)相关推荐

  1. 深入理解Java虚拟机-Java内存区域透彻分析

    Java虚拟机深入理解系列全部文章更新中- 深入理解Java虚拟机-Java内存区域透彻分析 深入理解Java虚拟机-常用vm参数分析 深入理解Java虚拟机-JVM内存分配与回收策略原理,从此告别J ...

  2. MMU内存管理单元(看书笔记)

    http://note.youdao.com/noteshare?id=8e12abd45bba955f73874450e5d62b5b&sub=D09C7B51049D4F88959668B ...

  3. 深入理解Java虚拟机—Java虚拟机内存

    之前的内容: 上一篇:深入理解Java虚拟机-Java历史以及Java虚拟机历史 下一篇:深入理解Java虚拟机-垃圾收集算法 一.运行时数据区分为五个区域 1. 程序计数器 他可以看作是当前线程所执 ...

  4. JAVA 虚拟机深入研究(二)——JVM虚拟机发展以及一些Java的新东西

    内容目录: JAVA 虚拟机深入研究(一)--关于Java的一些历史 JAVA 虚拟机深入研究(二)--JVM虚拟机发展以及一些Java的新东西 这是第二篇,我们来说说有关虚拟机的发展. 一说到虚拟机 ...

  5. 深入理解Java虚拟机阅读心得(二)

    深入理解Java虚拟机阅读心得(二) 垃圾收集 程序计数器.虚拟机栈.本地方法栈三个区域随线程而生,随线程而灭:这几个区域的内存分配和回收都具备稳定性,不需要过多的考虑回收的问题.而Java堆和方法区 ...

  6. Javascript权威指南看书笔记

    Javascript权威指南看书笔记 第一章 词法结构 javascript区分大小写,而html不区分大小写 unicode转义序列是由/u为前缀加4位16进制数组成 标识符必须以字母,下划线 _, ...

  7. 深入理解Java虚拟机(Java高阶读书笔记)

    深入理解Java虚拟机 - JVM高级特性与最佳实践(周志明)第2版 只要看:第2章.第3章.第4章.第5章简单看一看.第六章看6.1和6.2.第7章以及第12和13章.12和13属于并发里面的补充. ...

  8. Java虚拟机的体系结构

    java虚拟机由如下五个部分组成: 一组指令集 一组寄存器 一个栈 一个无用单元收集堆 一个方法区 1.Java指令集 Java虚拟机支持大约248个字节码,每个字节码执行一种基本的CPU运算,例如把 ...

  9. Java虚拟机学习 - 体系结构 内存模型(转载)

    一:Java技术体系模块图 二:JVM内存区域模型 1.方法区 也称"永久代" ."非堆",  它用于存储虚拟机加载的类信息.常量.静态变量.是各个线程共享的内 ...

最新文章

  1. Silverlight实用窍门系列:65.Silverlight的数据模板DataTemplate(一)使用数据模板
  2. linux 远程执行shell 获取返回值
  3. python加法赋值运算符为_Python学习-算术运算符,赋值运算符和复合运算符
  4. 【已解决】单片机串口通讯中RXD与TXD如何连线?
  5. golang java耗内存_分析golang内存占用情况
  6. MVC Controller中View(model)如何在 View中的index页面获得?
  7. python3 连接数据库~
  8. FTP服务端管理软件:Serv-U和filezilla
  9. Qt_MsgBox 非常简单 自定义实现类似QMessageBox的弹窗 静态调用
  10. 硬件开发学习需要掌握的基础知识
  11. 日常提醒(delphi源码)
  12. halcon之屌炸天的自标定
  13. Libata错误信息解析
  14. 丝路传说架设服务器维护,《丝路传说》一键整合服务端+GM工具+视频架设教程...
  15. C#项目启动会闪退问题解决
  16. lightning接口_新iPhone或将使用TypeC接口~
  17. 看淡生死,弥争当下!
  18. 2021-2027全球与中国锂电池三元正极材料市场现状及未来发展趋势
  19. 如何解决不能绘制网络模型,报错protobuf
  20. u盘装puppy linux,将PuppyLinux安装到U盘

热门文章

  1. python3.0实例_python3.0 模拟用户登录,三次错误锁定的实例
  2. 机器视觉技术及应用_工业机器人视觉技术的应用前景
  3. linux查看发起ddos攻击的ip,在Linux上使用netstat命令查证DDOS攻击的方法
  4. java监听焦点事件_【Java Swing公开课|Java Swing焦点事件监听器怎么用,看完这篇文章你一定就会了】- 环球网校...
  5. java背景图片加上组件_关于 java swing组件加背景图片的问题
  6. linux shell 博客,【博客侠】Linux Shell脚本系列:开始上手(1)
  7. sql server 修改字段不能为空_SQL-SQL介绍
  8. 校验html输入值为电话号码,js验证输入是否为手机号码或电话号码示例
  9. 螺旋天线有方向性吗_螺旋天线方向图
  10. linux源码文件名,Linux中文件名解析处理源码分析