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

【转载】深入理解Java虚拟机》笔记

    博客分类:
  • J2SE
 
阅读更多
【转自】http://www.admin10000.com/document/1163.html

在 C 语言里面我们想执行一段自己编写的机器指令的方法大概如下:
typedef void (*FUNC)(int);
char* str = "your code";
FUNC f = (FUNC)str;

也就是说,我们完全可以做一个工具,从一个文件中读入指令,然后将这些指令运行起来。上面代码中“编好的机器指令”当然指的是能在CPU上运行的,如果这里我还实现了一个翻译机器:从自己定义的格式指令翻译到CPU指令,那么就可以执行根据自定义格式的代码了。那么上面这段代码是不是相当于最简单的一个虚拟机了?下面来看JVM的总体结构:

ClassLoader的作用是装载能被JVM识别的指令(当然不只是从磁盘文件或内存去装载),那么我们先了解一下该格式:

魔数以及版本就不说了(满大街的文件格式都是这个东西),接着的便是常量池,其中无非是两种东西:

1. 字面常量(比如Integer、Long、String等);

2. 符号引用(方法是哪里的?什么样的?);

而我们知道,在JVM里面Class都是根据全限定名去找的,那么方法的描述当然也应该如此,那么就得到这些常量之间的关系如下:

在接下来的“访问权限”中表明了该Class是public还是private等,而this&super&interface则表面了“本类”、“继承自哪个类”、“实现了哪些接口”,实际上这里只是保存了代表这些信息的CONSTANT_Class_info的下标(u2)。

感觉这里的NameIndex和DescriptorIndex加起来和NameAndType有点像,那么为什么不直接用一个NameAndType的索引值表示?MethodInfo和FieldInfo之间最大的不同点就是Attributes。比如FieldInfo的属性表中存放的是变量的初始值,而MethodInfo的属性表中存放的则是字节码。那么我们来依次看这些Attributes,首先是Code:

有几个有意思的地方:

1. 从Class文件中可以知道在执行的过程中栈的深度;

2. 对于非静态方法,编译器会将this通过参数传递给方法;

3. 异常表中记录的范围是指令的行数(而不是源代码的);

4. 这里的异常是指try-catch中的,而与Code同级的异常表中的则是指throws出去的;

Exceptions则非常简单:

LineNumberTable保存了字节码和源码之间的关系,结构如下:

LocalVariableTable描述了栈帧中局部变量表的变量和源代码中定义的变量之间的关系,结构如下:

SourceFile指明了生成该Class文件的Java源码文件名(比如在一个Java文件中申明了很多类的时候会生成很多Class文件),结构如下:

Deprecated和Synthetic属性只存在“有”和“没有”的区别:

1. Deprecated:被程序作者定为不再推荐使用,通过@deprecated注释说明;

2. Synthetic:表示字段或方法是由编译器自动生成的,比如<init>;

这也就是为什么Code属性后面会有Attribute的原因?

类加载的时机就很简单了:在用到的时候就加载(废话!)。下来看一下类加载的过程:

执行上面这段过程的是:ClassLoader,这个东西还是非常重要的,在JVM中是通过ClassLoader和类本身共同去判断两个Class是否相同。换句话说就是:不同的ClassLoader加载同一个Class文件,那么JVM认为他们生成的类是不同的。有些时候不会从Class文件中加载流(比如Java Applet是从网络中加载),那么这个ClassLoader和普通的实现逻辑当然是不一样的,通过不同的ClassLoader就可以解决这个问题。

但是允许使用不同的ClassLoader又引发了新的问题:如果我也声明了一个java.lang.Integer,但是里面的代码非常危险,怎么办?这里就引出了双亲委派模式:

除了顶层的启动类加载器外,其余的类加载器都应该有父类加载器(通过组合实现),它在接到加载类的请求时优先委派给父类加载器去完成。

这样的话,在加载java.lang.Integer的时候会优先使用系统的类加载器,这样就不会加载用户自己写的。在Java程序员看到有3种系统提供的类加载器:

1. Bootstrap ClassLoader:负责加载<JAVA_HOME>\lib目录中的类库,无法被Java程序直接引用;

2. Extension ClassLoader:负责加载<JAVA_HOME>\lib\ext,开发者可以直接使用;

3. Application ClassLoader:加载ClassPath上所指定的类库,如果没有自己定义过自己的类加载器则会使用它;

这样默认的类会是有Application ClassLoader去加载类,然后如果发现要使用新的类型的时候则会递归地使用Application ClassLoader去加载(在前面的加载过程中提到)。这样,只有在自己的程序中能使用自己编写的ClassLoader去加载类,并且这个被加载的类是不能被别人使用的。

双亲委派模式不是一个强制性的约束,而是Java设计者推荐给开发者的类加载实现方式。双亲委派模式出现过的3次“破坏”:

1. 为了兼容JDK 1.0,建议使用者去覆盖findClass方法;

2. 在基础类要访问用户类的代码会出现问题(比如JNDI):线程山下文类加载器;

3. 用户的一些需求,比如HotSwap、OSGI等;

加载完完成后,接下来就要看程序是怎么运行的。栈帧是用于支持虚拟机进行方法调用和执行,帧的意思就是一个单位,在调用其他方法的时候会向栈中压入栈帧,结构如下:

在Class文件编译完成之后,在运行的时候需要多少个局部变量就已经确定(在前面Class文件中也已经看到过了),那么这里需要注意这个特性可能会引发GC(具体如何引发就不在这里细说了)。在栈中,总是底层的栈去调用高层的栈(并且一定的相邻的),那么他们在参数传递(返回结果)的时往往是通过将其压入操作数栈,有些虚拟机为了提高这部分的效率使得相邻栈帧“纠缠”在一起:

那么我们接下来要去看是方法是如何执行的,第一个问题就是执行哪个方法?在“面向过程”的编程中似乎不存在在个问题,但是在Java OR C++中这都是比较蛋疼的一个问题。原因就是平时不会这么用,但是你必须去搞明白= =。JVM确定目标方法的时候有两种方法:

1. 静态分派:根据参数类型和方法名称来决定调用哪个方法。但是,并不是说没有发现匹配的类型就报错,比如有:func(int a),而在调用func(‘a’)的时候也会调用该方法(当然是在没有func(char a)的前提下),这样给人的关键就有点像一个处理的链条。不管多么复杂,这些都是在编译期间确定的,因为这里是向上找的。

2. 动态分派:最普遍的就是Interface a = new Implements(),a调用方法到底应该是哪个类的在编译期间是无法确定的。其实动态分派实现起来也很简单:在调用方法的时候先拿到对象的实际类型。

其实“静态”和“动态”给人的感觉还是比较模糊的,“静态分派”给人的感觉是根据参数的类型向上查找方法,“动态分派”给人的感觉则是根据实例的真实类型向上查找。虚拟机优化动态分派的效率一般是为类在方法区中建立一个虚方法表:

虚方法表中存放各个方法实际入口地址,如果某个方法在子类中没有被重写,那么子类的虚方法表里面的地址入口和父类相同方法的地址入口是一致的,都指向父类的实现入口。如果子类重写了这个方法,子类方法表中的地址将会被替换为指向子类实现版本的入口地址。其实往简单里说,就是一个预处理。
分享到:
评论

相关推荐

    深入理解Java虚拟机JVM高级特性与最佳实践1

    《深入理解Java虚拟机JVM高级特性与最佳实践》是一本专注于Java开发人员提升技术水平的著作,由周志明撰写。这本书旨在填补Java技术体系中关于Java虚拟机(JVM)知识的空白,帮助读者深入理解JVM的工作原理及其对...

    深入Java虚拟机(原书第2版).pdf【附光盘内容】

     作者以易于理解的方式深入揭示了java虚拟机的内部工作原理,深入理解这些内容,将对读者更快速地编写更高效的程序大有裨益!  本书共分20章,第1-4章解释了java虚拟机的体系结构,包括java栈、堆、方法区、执行...

    深入理解java虚拟机视频教程

    深入理解java虚拟机视频教程,jvm原理,java虚拟机,jvm性能调优,内存模型,gc工作原理,内存分配,类的加载等等视频教程

    深入理解Java虚拟机学习笔记借鉴.pdf

    Java 虚拟机(JVM)自动内存管理机制 Java 虚拟机(JVM)自动内存管理机制是 Java 语言的一大特色,它使得 Java 程序员无需手动管理内存,从而提高了开发效率和程序稳定性。JVM 自动内存管理机制主要通过 JVM 的...

    深入理解Java虚拟机笔记(带目录).docx

    深入理解 Java 虚拟机笔记 Java 虚拟机(JVM)是 Java 语言的运行环境,它负责解释和执行 Java 字节码。下面是 Java 虚拟机相关的知识点: 虚拟机内存结构 Java 虚拟机的内存结构主要包括以下几个部分: * 方法...

    深入java虚拟机 高清pdf 高清高清高清

    《深入Java虚拟机》这本书是Java开发者深入了解JVM(Java Virtual Machine)的必备经典之作。它详尽地探讨了Java虚拟机的工作原理、内存管理、类加载机制、字节码执行以及性能优化等多个核心主题,旨在帮助开发者...

    深入理解Java虚拟机读书笔记之:第3章 安全(3)

    《深入理解Java虚拟机》是Java开发者必读的经典之作,其中第三章主要探讨了Java安全方面的内容。在Java中,安全是一个至关重要的概念,因为Java的设计目标之一就是提供一种可以在不同环境中安全运行的代码机制。本章...

    诸葛 BAT面试之深入理解Java虚拟机 9

    诸葛_BAT面试之深入理解Java虚拟机_9

    深入理解 Java 虚拟机 - v1.0.pdf

    虚拟机是一种抽象化的计算机,通过在实际的计算机上仿真模拟各种...Java虚拟机屏蔽了与具体操作系统平台相关的信息,使得Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。

    深入理解JAVA虚拟机.xmind

    深入理解JAVA虚拟机.xmind

    深入理解Java虚拟机.xmind

    自己看《深入理解Java虚拟机》(第二版)所做的一些笔记。因为个人水平有限,能够理解的也只有前面几章的内容,后面的内容觉得看了也不是很理解,就没有记在里面。希望能对大家有所帮助,也希望能和大家一起进步。

    深入理解Java虚拟机(第二版)_java_

    《深入理解Java虚拟机(第二版)》是Java开发者必读的经典著作,它全面而深入地探讨了Java虚拟机(JVM)的工作原理和技术细节。这本书涵盖了从内存管理、类加载机制、字节码执行到垃圾收集算法等多个关键领域,为...

    深入理解Java虚拟机.rar_JAVA虚拟机_java_深入理解JVM:pdf_深入理解Java_深入理解jvm

    了解jvm的pdf,高清pdf,希望大家下载

    深入JAVA虚拟机 不那么完美的第二版.pdf.zip

    虽然《深入JAVA虚拟机》的第二版可能在物理形态上有些许不足,但其内容依然对理解JVM的运作机制有着重要的指导意义。学习这些知识点,有助于Java开发者提升代码的运行效率,解决内存问题,以及进行性能优化。

    深入理解Java虚拟机(jvm性能调优+内存模型+虚拟机原理).zip

    《深入理解Java虚拟机》是一本深度探讨Java虚拟机(JVM)的著作,涵盖了JVM性能调优、内存模型以及虚拟机原理等多个关键领域。本文将基于这些主题,详细阐述其中的重要知识点。 首先,我们要了解Java虚拟机(JVM)...

    深入Java虚拟机——本地方法栈.pdf

    Java虚拟机(JVM)是Java程序运行的基础,它提供了执行环境和各种内存区域,以支持Java代码的高效运行。本地方法栈是JVM的一部分,它主要负责处理与本地方法(通常是由C或C++编写)相关的调用。本地方法栈在Java线程...

    深入理解Java虚拟机——Java发展史.xmind

    这是自己读《深入理解Java虚拟机》时候用XMind建立的思维导图,目的是为了能够帮助自己整理、梳理相关的知识以及方便自己日后的回顾,帮助自己建立起关于JVM的知识体系,里边也有一些对相关内容的补充,通过备注的...

    深入java虚拟机.pdf

    深入 Java 虚拟机.pdf Java 虚拟机(Java Virtual Machine,JVM)是 Java 语言的 runtime 环境,是 Java 程序执行的核心组件。它提供了一个平台无关的环境,允许 Java 程序在不同的操作系统和硬件平台上运行。 一...

    学习深入理解Java虚拟机的前几章笔记

    ### 学习深入理解Java虚拟机的前几章笔记 #### JVM内存模型 Java虚拟机(JVM)的内存模型主要分为两大类:线程共享区和线程私有区。 ##### 线程共享区 - **堆**:是所有线程共享的内存区域,在这里存放着对象实例...

    深入理解JAVA虚拟机实用技巧案例讲解.ppt

    **深入理解JAVA虚拟机实用技巧案例讲解** Java虚拟机(JVM)是Java程序的核心运行环境,它负责解析字节码并执行Java程序。在实际开发中,了解JVM的工作原理和优化技巧对于提高程序性能至关重要。以下是一些关键知识...

Global site tag (gtag.js) - Google Analytics