java虚拟机学习笔记

Java技术的核心就是Java虚拟机,因为所有的Java程序都在虚拟机上运行。Java程序的运行需要Java虚拟机、Java API和Java Class文件的配合。Java虚拟机实例负责运行一个Java程序。当启动一个Java程序时,一个虚拟机实例就诞生了。当程序结束,这个虚拟机实例也就消亡。

  java虚拟机结构图如下:

                     


1、Java运行时数据区域

当类加载器将class文件加载到jvm后,Java虚拟机在执行java程序的过程中会把它管理的内存划分为若干个不同的数据区,java虚拟机所管理的内存将会包含以下几个运行时数据区域:

  1. 程序计数器(Program Counter Register)
  2. java虚拟机栈(Java Virtual Macchine Stacks)
  3. 本地方法栈(Native Method Stack)
  4. java堆(Java Heap)
  5. 方法区(Method Area)
  6. 运行时常量池(Runtime Constant Pool)

  1-1、程序计数器:

  程序计数器是一块较小的内存,可以被认作时当前线程所执行的字节码的行号指示器。字节码解释器通过改变计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖计数器实现。每个线程都需要一个独立的计数器,所有程序计数器不是线程共享的。

  当线程执行的是java方法时,计数器记录当前正在执行的虚拟机字节码指令的地址,如果执行的是本地方法,则计数器值为空(Undefined),此内存也是唯一一个在虚拟机规范中没有规定任何OutOfMemoryError情况的区域。  

  1-2、java虚拟机栈:

  该区域也是线程私有的,它的生命周期与线程相同。每个方法在执行时都会创建一个帧栈用于存储局部变量表、操作数栈、动态链接、方法出口信息等,该区域规定了两种异常状况:StackOverflowError和OutOfMemoryError

  每个方法从调用到执行完成的过程都会有一个人对应的帧栈在虚拟机栈中入栈出栈。栈由许多栈帧组成,一个栈帧包含一个Java方法调用的状态。当线程调用一个Java方法时,虚拟机压入一个新的栈帧到该线程的栈中,当该方法返回时,这个栈帧就从栈中弹出。Java栈存储线程中Java方法调用的状态--包括局部变量、参数、返回值以及运算的中间结果等。Java虚拟机没有寄存器,其指令集使用Java栈来存储中间数据。这样设计的原因是为了保持Java虚拟机的指令集尽量紧凑,同时也便于Java虚拟机在只有很少通用寄存器的平台上实现。另外,基于栈的体系结构,也有助于运行时某些虚拟机实现的动态编译器和即时编译器的代码优化。

  1-2-1、局部变量区

  局部变量区被组织为以字长为单位、从0开始计数的数组。字节码指令通过从0开始的索引使用其中的数据。类型为int, float, reference和returnAddress的值在数组中占据一项,而类型为byte, short和char的值在存入数组前都被转换为int值,也占据一项。但类型为long和double的值在数组中却占据连续的两项。

  1-2-2、操作数栈

  和局部变量区一样,操作数栈也是被组织成一个以字长为单位的数组。它通过标准的栈操作访问--压栈和出栈。由于程序计数器无法被程序指令直接访问,Java虚拟机的指令是从操作数栈中取得操作数,所以它的运行方式是基于栈而不是基于寄存器。虚拟机把操作数栈作为它的工作区,因为大多数指令都要从这里弹出数据,执行运算,然后把结果压回操作数栈。

  1-2-3、帧数据区

  除了局部变量区和操作数栈,栈帧还需要帧数据区来支持常量池解析、正常方法返回以及异常派发机制。每当虚拟机要执行某个需要用到常量池数据的指令时,它会通过帧数据区中指向常量池的指针来访问它。除了常量池的解析外,帧数据区还要帮助虚拟机处理Java方法的正常结束或异常中止。如果通过return正常结束,虚拟机必须恢复发起调用的方法的栈帧,包括设置程序计数器指向发起调用方法的下一个指令;如果方法有返回值,虚拟机需要将它压入到发起调用的方法的操作数栈。为了处理Java方法执行期间的异常退出情况,帧数据区还保存一个对此方法异常表的引用。

  1-3、本地方法栈

  本地方法栈与虚拟机栈的作用是相似的,区别仅仅是虚拟机栈为虚拟机执行Java方法,而本地方法栈执行虚拟机使用到的Native方法。

  1-4,、java堆

  Java堆一般是Java虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的,是非线程安全的,在虚拟机启动时创建。

此区域的唯一目的是存放对象实例,几乎所有对象实例和数组(数组实质也是对象)都是在这里分配内存(Java虚拟机规范的原文:The heap is the runtime data area from which memory for all class instance and arrays is allocated.)但是随着虚拟机相关技术的发展,栈上分配等技术将会导致所有对象分配在堆上也不再是那么“绝对”了。  

  因为几乎所有对象都分配在Java堆上,所以Java堆也是垃圾收集器管理的主要区域。从内存角度看,由于现在垃圾收集器基本采用分算法,所欲Java堆又可以细分为:新生代(young area)和老年代(old area),(java8后移除永久代);再细致一点又可以分为Eden、From Survivor 、To Survivor。

  VisualVM的(JAVA8)Visual GC视图如下:

 可以看到Java堆首先被分为新生代和老年代两块区域,新生代又细分为eden、s0、s1三块区域,如此划分应是为了提高虚拟机效率。

  1-5、方法区

  方法区与Java堆一样,也是线程共享的,它被用来存储已被虚拟机加载的类信息、常量、静态变量、即使编译器编译后的代码等数据。java虚拟机对方法区的限制非常宽松,除了和Java堆一样不需要连续的内存和可以选择固定大小或者可扩展外,还可以选择不实现垃圾收集。

 

  1-6、运行时常量池

  运行时常量池是 方法区 的一部分,用于存放编译期间生成的各种字面量和符号引用,这部分内容是在类加载后进入方法区运行时常量池中存放。

java虚拟机笔记-1的更多相关文章

  1. Java虚拟机笔记(五):JVM中对象的分代

    为什么要分代 为什么需要把堆分代?不分代不能完成他所做的事情么?其实不分代完全可以,分代的唯一理由就是优化GC性能.你先想想,如果没有分代,那我们所有的对象都在一块,GC的时候我们要找到哪些对象没用, ...

  2. Java虚拟机笔记(四):垃圾收集器

    前言 前一篇文章介绍了内存的垃圾收集算法,现在介绍下内存回收的具体实现--垃圾收集器. 由于Java虚拟机规范中对垃圾收集器应该如何实现并没有任何规定,因此不同的厂商,不同版本的虚拟机所提供的垃圾收集 ...

  3. Java虚拟机笔记(三):垃圾收集算法

    一.标记-清除(Mark-Sweep)算法 标记清除算法是最基础的收集算法,其他收集算法都是基于这种思想. 标记清除算法分为“标记”和“清除”两个阶段:首先标记出需要回收的对象,标记完成之后统一清除对 ...

  4. Java虚拟机笔记(二):GC垃圾回收和对象的引用

    为什么要了解GC 我们都知道Java开发者在开发过程中是不需要关心对象的回收的,因为Java虚拟机的原因,它会自动回收那些失效的垃圾对象.那我们为什么还要去了解GC和内存分配呢? 答案很简单:当我们需 ...

  5. Java虚拟机笔记(一):类加载机制

    一.概述 虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制. 二.类加载的生命周期 类从被加载到 ...

  6. 深入理解java虚拟机笔记Chapter12

    (本节笔记的线程收录在线程/并发相关的笔记中,未在此处提及) Java内存模型 Java 内存模型主要由以下三部分构成:1 个主内存.n 个线程.n 个工作内存(与线程一一对应) 主内存与工作内存 J ...

  7. Java虚拟机笔记 – JVM 自定义的类加载器的实现和使用2

    1.用户自定义的类加载器: 要创建用户自己的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的findClass(String name)方法即可,该方法根据参数指定类的名 ...

  8. 深入理解Java虚拟机笔记

    1. Java虚拟机所管理的内存 2. 对象创建过程 3. GC收集 4. HotSpot算法的实现 5. 垃圾收集器 6. 对象分配内存与回收细节 7. 类文件结构 8. 虚拟机类加载机制 9.类加 ...

  9. 深入理解java虚拟机笔记之一

    Java的技术体系主要有支撑java程序运行的虚拟机,提供各开发领域接口支持Java API,java编程语言及许多第三方java框架( 如Spring,Structs等)构成. 可以把Java程序设 ...

随机推荐

  1. 初步了解oracle

    1. Oracle的创始人 2. Oracle版本含义 3. Oracle安装:用户种类及初始密码 在oracle10g\11g中默认scott被锁定. 4. Oracle数据库的启动 a) 启动两个 ...

  2. Python + logging输出到屏幕,将log日志写入到文件

    logging提供了一组便利的函数,用来做简单的日志.它们是 debug(). info(). warning(). error() 和 critical(). logging函数根据它们用来跟踪的事 ...

  3. [Usaco2007 Jan]Telephone Lines架设电话线(最短路,二分)

    [Usaco2007 Jan]Telephone Lines架设电话线 Description FarmerJohn打算将电话线引到自己的农场,但电信公司并不打算为他提供免费服务.于是,FJ必须为此向 ...

  4. process-hacker

    https://github.com/processhacker/processhacker#process-hacker // begin_phapppub typedef enum _PH_KNO ...

  5. 微服务+DDD代码结构例子

    这是一个基本的微服务+DDD演示例子: 基于 Spring Boot 1.5.6 , Spring Cloud Edgware.SR4 Version 微服务 + DDD,个人觉得应该是首先是从微服务 ...

  6. jQuery入门、jQuery选择器、jQuery操作

    一.什么是jQuery及如何使用 1.1 jQuery 简介 jQuery是一个兼容多浏览器的javascript函数库(把我们常用的一些功能进行了封装,方便我们来调用,提高我们的开发效率.),核心理 ...

  7. 手写hashmap算法

    /** * 01.自定义一个hashmap * 02.实现put增加键值对,实现key重复时替换key的值 * 03.重写toString方法,方便查看map中的键值对信息 * 04.实现get方法, ...

  8. sklearn.metrics.mean_absolute_error

    注意多维数组 MAE 的计算方法 * >>> from sklearn.metrics import mean_absolute_error >>> y_true ...

  9. 运行 tensorboard

    使用下面命令总是报错: tensorboard --logdir=mylogdir tensorboard --logdir='./mylogdir' 正确命令 tensorboard --logdi ...

  10. 【leetcode】1079. Letter Tile Possibilities

    题目如下: You have a set of tiles, where each tile has one letter tiles[i]printed on it.  Return the num ...