虚拟机:
指通过软件模拟的具有完整硬件系统功能的、运行在一个完全隔离环境中的完整计算机系统
JVM是Java程序运行的环境,同时是一个操作系统的一个应用程序进程,因此它有自己的生命周期,也有自己的代码和数据空间.
JVM的内部体系结构分为三个子系统和两大组件,分别是:类装载器(ClassLoader)子系统、执行引擎子系统和GC子系统,组件是内存运行数据区域和本地接口。
操作系统装入JVM(Java XXX)
1.创建JVM装载环境和配置
2.装载JVM.dll
3.初始化JVM.dll并挂界到JNIENV(JNI调用接口)实例
4.调用JNIEnv实例装载并处理class类。
结构图:
深入理解Java虚拟机(第二版)的描述如下:
Java程序在运行时,需要在内存中的分配空间。为了提高运算效率,就对数据进行了不同空间的划分,因为每一片区域都有特定的数据处理方式和内存管理方式。
具体划分为如下5个内存空间:
每个线程都有一个PC寄存器
在线程创建时创建
指向下一条待执行字节码指令的地址
线程私有
保存装载的类信息
类型的常量池
方法字节码,方法信息
对于每一个被类装载子系统装载的类型,虚拟机都会保存下列数据到方法区:
类型的全限定名
类型超类的全限定名(java.lang.Object没有超类)
类型是类类型还是接口类型
类型的访问修饰符
任何直接超接口的全限定名有序列表
除了上述基本类型信息,还将保存如下信息:
类型的常量池
字段信息(包括字段名、字段类型、字段修饰符)
方法信息(包括方法名、返回类型、参数的数量和类型、方法修饰符)
常量以外的所有类变量(其实就是类的静态变量,因为静态变量是所有实例共享的,且与类型直接相关,所以他们是类一级的变量,作为类的成员被保存在方法区)
所有线程共享Java堆
对象实例和数组都保存在堆中
线程私有,生命周期和线程相同
栈由一系列栈帧组成
栈保存一个方法的局部变量、操作数栈等
每个方法被调用的时候都会创建一个栈帧, 每一个方法被调用直至执行完成的过程就对应着一个栈帧在虚拟机中从入栈到出栈的过程。
局部变量表存放了编译期可知的各种基本数据类型和对象引用,所需内存空间在编译期确定
每一个线程有一个本地内存。本地内存和主存独立。本地内存存放主存中变量的值的拷贝。
当数据从主内存复制到本地存储时,必须出现两个动作:第一,由主内存执行的读(read)操作;第二,由本地内存执行的相应的load操作;
当数据从本地内存拷贝到主内存时,也出现两个操作:第一个,由工作内存执行的存储(store)操作;第二,由主内存执行的相应的写(write)操作。
每一个操作都是原子的,即执行期间不会被中断
对于普通变量,一个线程中更新的值,不能马上反应在其他变量中。如果需要在其他线程中立即可见,需要使用volatile关键字作为标识。
JMM -> Java Memory Model
可见性
一个线程修改了变量,其他线程可以立即知道
保证可见的方法:
volatile
synchronized (unlock之前,写变量值回主存)
final(一旦初始化完成,其他线程就可见)
有序性
在本线程内,操作都是有序的
在线程外观察,操作都是无序的(指令重排或主内存同步延迟)
指令重排
线程内串行语义
所谓的线程安全,其实就是不同线程对同一个资源的访问和修改引发的数据不一致问题。
一旦多个线同时对主内存中的同一个资源进行操作,那么就可能导致资源状态的不一致。
Java语言并不要求常量一定只有编译期预置入Class的常量表的内容才能进入方法区常量池,运行期间也可将新内容放入常量池(最典型的String.intern()方法)
原文:http://blog.csdn.net/jiangxishidayuan/article/details/50992672