内存分配以及回收

Java虚拟机运行时数据区,分为以下几个模块,包含所有线程共有的数据区和线程单独享有的数据区。

程序计数器:字节码行号,通过这个计数器来选取下一条需要执行的指令,线程独有。

虚拟机栈:线程私有。方法在执行时会创建一个栈帧,用于存储局部变量表等。局部变量表中存放了编译器可知的基本数据类型、对象引用、returnAddress(指向了一条字节码指令的地址)

本地方法栈:与虚拟机栈类似,只不过这个地方是为native方法服务。

堆:线程共用。存放对象实例。

方法区:线程共用。存储已经被虚拟机加载的类信息、常量、静态变量等。

运行时常量池:用于存放编译期生成的字面量和符合引用。字面量就是我们所说的常量概念,如文本字符串、被声明为final的常量值等。符号引用是一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义地定位到目标即可,一般包括下面三类常量:类和接口的全限定名、字段的名称和描述符、方法的名称和描述符。

JVM通过根搜索算法来判定对象是否可以回收,一般对于不能从根(GC Roots)搜索到的对象是可以被回收的。

能够被作为GC Roots对象有:虚拟机栈本地变量表中引用的对象(也就是正在调用的方法中引用的);方法区中静态属性或常量引用的对象;本地方法栈引用的对象。

可以被回收的对象并不一定绝对被回收,JVM先做一次标记和筛选,把那些覆盖了finalize方法的对象筛选出来然后触发finalize方法,如果在finalize方法中对象复活,则不回收,否则回收,且finalize方法仅会被触发一次。

垃圾回收算法

标记-清除:把标记为待回收的对象空间清除,容易造成大量空间碎片;

复制算法:将内存分为三个区域,一个较大的eden区和两个较小的survivor区。每次GC都把存活的对象挪到其中一个servivor区,然后把eden全部清除。只对每次GC时存活对象较少时比较有效,适用于新生代;

标记-整理:把标记后存活的对象向一个方向移动,然后清除其它空间。比较适合老年代。

内存分配与回收策略

对象默认优先分配在新生代;

大对象直接分配到老年代;

长期存活的对象转移到老年代:虚拟机给每个对象定义一个对象年龄,没发生一次minor GC,年龄就增加一次,超过默认值之后就会进入到老年代。

动态对象年龄判定:对象不一定是必须到了默认年龄才能进入老年代,如果一个eden区中所有相同年龄的对象大小综合超过eden一半的空间,那么大于等于这个年龄的对象也会进入老年代。

类文件结构

class文件是二进制组成的,class有两种数据类型:无符号数和表。

无符号数是基础数据类型,其中u1表示1个字节、u2表示2个字节(一个字节8个bit,而4个bit可以表示1个16进制的数,也就是说1个字节可以用2个16进制数表示);

表是由多个无符号数或其它表构成的。

magic是4个字节,也就是8个16进制数,固定为CAFEBABE;后面分别是两个版本号。

常量池:跟着版本号之后的就是常量池(字面量和符号引用)。由于无法确认一个类中常量池有多少常量,所有先有一个值来标志有多少个,然后再是常量具体信息。

访问标志:常量池之后跟着的是2个字节的访问标志。需要被标志的内容包括:是否public、是否final、是否abstract、是类或接口

访问标志之后是类索引(用于确定该类的全限定名)、父类索引(用于确定父类的全限定名)、接口所有集合(实现的接口可能不止一个)

字段表集合:描述接口或类中声明的变量,包含类变量和实例变量。

方法表集合:描述类或接口中声明的fangfa。

属性表结合:

code属性:java方法体中的代码经javac编译后会存储在code属性中(接口中方法或抽象方法没有code属性)

Exceptions属性:列举出方法throws后面抛出的异常;

其它各属性不再一一列举。

类加载机制

类加载的时机

主动引用的几种情况才会加载(前提是此类没有被加载过)

new一个对象、引用类的static变量(final变量除外)、调用类的static方法;

对类进行反射调用时;

初始化一个类时,如果父类没有被初始化,则先初始化父类;

虚拟机启动时,初始化包含main方法的那个类

被动引用不会触发初始化

调用父类静态方法,不会初始化子类;

通过数组定义引用类,不会触发初始化;

引用静态常量不会触发。

加载过程

通过一个类全限定名获取定义此类的二进制字节流(一般是class文件)

将二进制字节流转化为方法区中的运行时数据结构

在内存(堆)中生成这个类的Class类的对象,作为方法区这个类的各个数据的访问入口

连接过程

验证阶段:文件格式验证(是否符合Class文件规范)、元数据验证(是否符合java语法规范)、字节码验证(确保语义是符合逻辑的)、符合引用验证。

准备阶段:正式为类变量分配内存并设置初始值。

有两点需要注意:

一,此处只为类变量分配内存(static修饰的),不包含实例变量;

二,设置的初始值是这个类型的0值,不是实际值(但被final修饰的赋的就是实际值)

解析阶段:将符合引用替换为直接引用

初始化过程

初始化过程主要是执行类构造器方法

方法主要是手机所有类变量的赋值动作,和静态语句块(staic {});

虚拟机会保证方法在父类中先调用,这样说明父类的static语句块要比子类的static变量赋值操作先执行,以下代码中,字段B的值将会是2

这也说明了一个问题:new一个对象时,静态变量赋值和静态语句块会在类的构造方法前执行。

类加载器

比较两个类对象是否相等,只有加载两个类加载器的完全一样,才有意义;

如果一个类加载器收到一个类加载请求,它首先会请求委派给父类加载器完成,父类无法完成时,子类加载器才进行加载。

虚拟机字节码执行引擎

运行时栈帧结构

局部变量表:存放方法参数和局部变量。每个变量以slot为单位,slot可以复用

注意,如果没有int a = 0这一行代码,placeholder是不会被回收的,因为如果不加这行代码,就没有任何对局部变量表的读写操作,这个slot就不会被占用。

操作数栈:方法执行过程中,会有各种字节码出栈入栈

动态链接:一部分符合引用在类加载时转化为直接引用,这是静态机械;而一部分则是运行时转化为直接应用,这叫动态链接

方法调用和分派

所有的方法在Class文件中都是一个符合引用,而一部分方法在类加载时就直接解析为直接引用。这种方法必须是“编译时已知,运行时不可变”,就是静态方法和私有方法两大类

静态分派:依赖静态类型来定位方法执行版本称为静态分派,典型应用是重载。

Human是静态类型,后面的Man和Women则是实际类型。

静态类型在编译器可知,而动态类型则是在运行时才能知道。

动态分派:运行期间根据实际类型来确定方法执行版本,典型应用是覆盖。

结果是

内存模型及线程安全

JMM规定所有内存都存储于主内存中,每条线程还有自己的工作内存。

变量的读取、赋值操作必须在工作内存中进行。

内存直接的交互操作,主要有以下8种操作:

8种操作需要满足以下规则

volatile关键字

volatile关键字保证了变量的所有线程的可见性,但并非是线程安全的。

两种情况下是线程不安全的:

一,变量依赖于自身(比如i++之类的)

二,变量依赖于其它变量(比如i=a+3)

volatile禁止语义重排序

volatile的具体实现

a java虚拟机_Java虚拟机相关推荐

  1. 如何创建 java虚拟机_Java虚拟机如何创建对象?

    大草原的日落.jpg Java程序中无时无刻都有对象被创建出来.在语言层面上,对象创建(克隆.反序列化)仅仅是一个new关键字而已,而在虚拟机中,对象创建(仅限于普通对象,不包括数组和Class对象等 ...

  2. java jvm虚拟机_Java虚拟机(JVM)简介

    java jvm虚拟机 什么是JVM Java虚拟机(JVM)是使计算机能够运行Java程序的抽象计算机. JVM有三个概念: 1.规格 2.实施 3.实例. 该规范是正式描述JVM实现要求的文档. ...

  3. java虚拟_Java虚拟机(JVM)工作原理

    虽然本教程的内容为 x86 处理器的原生汇编语言,但是了解其他机器架构如何工作也是有益的.JVM 是基于堆栈机器的首选示例.JVM 用堆栈实现数据传送.算术运算.比较和分支操作,而不是用寄存器来保存操 ...

  4. java 机器码 虚拟机_Java虚拟机:源码到机器码

    无论什么语言写的代码,其到最后都是通过机器码运行的,无一例外.那么对于 Java 语言来说,其从源代码到机器码,这中间到底发生了什么呢?这就是今天我们要聊的. 如下图所示,编译器可以分为:前端编译器. ...

  5. java 回收器_Java虚拟机-经典垃圾回收器

    上图列举了七种作用于不同分代的垃圾收集器,如果两个收集器存在连线就说明可以搭配使用.收集器所处的区域表示它所属的年轻代还是老年代 属于年轻代的回收器 Serial收集器 简单高效且内存消耗小,适用于客 ...

  6. java6虚拟机_Java 虚拟机之六:javap工具

    一:简介 javap是JDK自带的反汇编器,可以查看java编译器为我们生成的字节码.通过它,我们可以对照源代码和字节码,从而了解很多编译器内部的工作. javap命令的常用参数有: -l 打印行和本 ...

  7. 显卡给2个虚拟机_Java虚拟机线上问题排查的2个基本操作,你知不知道?

    前言 对于后端程序员,特别是 Java 程序员来讲,排查线上问题是不可避免的.各种 CPU 飚高,内存溢出,频繁 GC 等等,这些都是令人头疼的问题.楼主同样也遇到过这些问题,那么,遇到这些问题该如何 ...

  8. java 虚拟机规范_Java虚拟机规范----Java虚拟机结构

    Java体系和一些基本概念 Java平台的结构图: JVM与JRE.JDK关系? JVM:Java Virtual Machine(Java虚拟机),负责执行符合规范的Class文件 JRE: Jav ...

  9. java虚拟机 函数表_java虚拟机的基本结构如图

    1 java虚拟机的基本结构如图: 1)类加载子系统负责从文件系统或者网络中加载Class信息,加载的类信息存放于一块称为方法区的内存空间.除了类的信息外,方法区中可能还会存放运行时常量池信息,包括字 ...

最新文章

  1. 逻辑电路 - 与非门Nand Gate
  2. 安卓手机可以连接斑马系统吗_Zebra斑马 StageNow 安卓系统移动设备快速部署工具...
  3. C指针原理(19)-C指针基础
  4. boost::graph模块使用breadth_first_search()实现GGCL算法的测试程序
  5. 知乎:GAN 的发展对于研究通用人工智能有什么意义?
  6. SAP Spartacus cx-page-layout 属性运行时的赋值原理, set 是如何被框架调用的?
  7. 转载:CEO如何“养好CIO同时管好CIO”?
  8. linux上的定时器上的jiffies,Linux kernel -- 定时器/jiffies
  9. 如何修复XML内存“泄漏”
  10. 弹性地基梁板的计算理论_造价人常用小帮手:30个实用小软件+44套计算表,绝对实用...
  11. 正月十五元宵节各种设计师需要的PSD分层展板\晚会横幅
  12. HDU多校练习第一场4608——I_Number
  13. 安卓手机怎么设置蓝牙耳机弹窗动画_AirPods Pro 搭配安卓一个月深度体验
  14. 基于Java坦克大战小游戏设计(3)
  15. 退出qemu_qemu虚拟机的关机方式
  16. 元宵节没用智能名片在互联网发贺卡,那就OUT了
  17. 计算机硬盘只显示c盘,电脑只显示C盘我们应该怎么办
  18. 滤波器基础05——巴特沃斯、切比雪夫与贝塞尔滤波器
  19. QUECTEL上海移远4G通讯CAT4模组EC20CEFAG模块串口调试指南之01物联网模组简介
  20. 新网(万网)账户间域名的转移

热门文章

  1. 图解面试题:找出数组中重复的数字?
  2. 使用SharedPreferences存储和读取数据
  3. Oracle 创建表 练习题
  4. Springboot遇到的问题
  5. Python操作excel(.xlsx)封装类MyPyExcel V2.0
  6. Modbus通信协议之CRC16冗余循环校验函数
  7. python 发红包import random用redenv,Python微信发红包编码案例 微信发红包的架构模式 - push博客...
  8. php类的举例,用类来代替递归方法,用php举例_php _ 搞代码
  9. oracle 列 连续,oracle中某列连续相同值的记录数统计(一个简单的例子)
  10. SpringAop @Pointcut(“@annotation“)\@Aspect练习