1.JVM内存结构
Java代码是运行在虚拟机上的,而虚拟机在执行Java程序的过程中会把管理的内存划分为若干个不同的数据区域。其中有些区域是随着虚拟机进程的启动而存在,而有些区域则依赖用户线程的启动和结束而建立和销毁。而这些区域会被划分为五个区域,具体的如下:
方法区:方法区与是所有线程所共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、及时编译器编译后的代码等数据。当方法区无法分配足够内存时,将会抛出OutOfMemoryError异常
堆:堆是Java虚拟机所管理的内存中最大的一块。java堆是被所有线程所共享的一块内存区域,虚拟机启动时创建。是GC(垃圾收集器)管理的主要区域。
虚拟机栈:虚拟机栈描述的是java方法执行的内存模型,方法的执行的同时会创建一个栈祯,用于存储方法中的局部变量表、操作数栈、动态链接、方法的出口等信息,每个方法从调用直到执行完成的过程,就对应着一个栈祯在虚拟机栈中入栈到出栈的过程 。
本地方法栈:本地方法栈和虚拟机栈很相似,不过本地方法栈中调用的都是本地方法。会抛出StackOverFlowError异常、OutOfMemoryError异常
程序计数器:指向当前线程所执行的字节码指令的地址,也就是当前代码执行到哪了,通常也叫做行号指示器。
2.Java内存模型
Java内存模型也就是JMM(Java Memory Model),其只是一个抽象的概念,并不是真实存在的。
由于java中多线程之间是通过共享内存进行通讯的,所以其就会出现并发的三大特性:原子性,一致性和有序性。而JMM就是围绕着这些特性而建立的模型。JMM定义了一些语法集,这些语法集映射到Java语言中就是: volatile、 synchronized等关键字。
JMM将共享数据部分的内存称为主内存,而在并发编程中的多个线程每一个线程都维护了一个自己的本地内存(抽象概念),操作数据是通过将主内存中的数据复制到本地内存,在本地内存中操作,之后再同步到主内存。而JMM主要就是控制本地内存和主内存之间的数据交互。
总的来说JMM是一种规范,目的是解决多线程间共享内存进行通信时,存在的本地内存数据不一致、编译器会对代码指令重排序、处理器会对代码乱序执行等带来的问题。目的是保证并发编程场景下的原子性、可见性、有序性
其抽象结构为:
3.Java对象模型
Java对象模型是java对象自身的存储模型。java对象在内存中由三部分构成:对象头,实例数据和对齐填充
HotSpot虚拟机中,设计了 OOP-KlassModel,其中OOP是指普通对象指针,而Klass用来描述对象实例的具体类型。
其中OOP-KlassModel模型为:
对象头:Java对象头一般占有2个机器码(在32位虚拟机中,1个机器码等于4字节,也就是32bit,在64位虚拟机中,1个机器码是8个字节,也就是64bit),一个记录MarkWord,一个记录元数据指针。特殊的就是当存储的对象为数组的时候,会占用三个机器码,有一个机器码记录的是数组的长度。
- Mark Word
锁状态 | 25bit | 4bit | 1bit(是否偏向锁) | 2bit(锁标志位) |
---|---|---|---|---|
无锁 | 对象的hashCode | 分代年龄 | 0 | 01 |
偏向锁 | 前23位存的位线程ID,后2位存的位Epoch(本质位一个时间戳,表示偏向锁的有效性) | 分代年龄 | 1 | 01 |
轻量级锁 | 指向栈中锁记录的指针 | 00 | ||
重量级锁 | 指向栈中锁记录的指针 | 10 | ||
GC标记 | 空 | 11 |
- 元数据指针
它主要指向类的数据也就是指向方法区中的位置,通过这个指针,我们就可以知道该实例属于哪个类,长度通常为32bit。 - 数组长度
只有数组对象才有,在32位或者64位JVM中,长度都是32bit。
实例数据
主要存放的是类的数据信息
对齐填充
仅仅是为了填充数据使字节达到8的倍数,并不具有什么实际意义。
4.总结
- JVM内存结构与java虚拟机运行时数据区域有关
- Java内存模型也就是JMM与Java并发编程有关
- Java对象模型就是Java对象的存储结构,和Java对象在虚拟机中的存储有关