JVM规范
jvm本身是软件层级,jvm本身是跑在操作系统的软件,jvm只是做了一些规范。
jvm层级队列两个进行组合,组成了四种屏障,这是jvm虚拟机规定的规范。
LoadLoad屏障
对于这样的语句Load1;LoadLoad;Load2
在Load2及以后续读取操作要读取的数据被访问前,保证Load1要读取的数据被读取完毕
StoreStore屏障
对于这样的语句Store1;StoreStore;Store2
在Store2及后续写入操作执行前,保证Store1的写入操作对其他处理器可见
LoadStore屏障
对于这样的语句Load1;LoadStore;Store2
在Store2及后续写入操作被刷出前,保证Load1要读取的数据被读取完毕
StoreLoad全能屏障
对于这样的语句Store1;StoreLoad;Load2
在load2及后续所有读取操作执行前,保证Store1的写入对所有处理器可见
volatile的实现细节
字节码层面(ACC_VOLATILE)
jvm层面
os和硬件层面
JAVA8大原子操作(虚拟机规范)(已弃用)
lock:主内存,标识变量为线程独占
unlock:主内存,解锁线程独占变量
read:主内存,读取内容到工作内存
load:工作内存,read后的值放入线程本地变量副本
use:工作内存,传值给执行引擎
assign:工作内存,执行引擎结果赋值给线程本地变量
store:工作内存,存值到主内存给write备用
write:主内存,写变量值
hanppens-before原则(JVM规定重排序必须遵守的规则)
程序次序规则:同一个线程内,按照代码出现的顺序,前面的代码先行于后面的代码,准确的说是控制流顺序,因为要考虑到分支和循环结构
管程锁定规则:一个unlock操作先行发生于后面对同一个锁的lock操作。
volatile变量规则:对一个volatile变量的写操作先行发生于后面对这个变量的读操作。
线程启动规则:Thread的start()方法先行发生于这个线程的每一个操作
线程终止规则:线程的所有操作都先于此线程的的终止检测,可以通过Thread.join()方法结束、Thread.isAlive()的返回值等手段检测线程的终止
线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过Thread.interrupt()方法检测线程是否中断。
对象终结规则:一个对象的初始化完成先于发生它的finalize()方法的开始。
传递性:如果操作A先行于操作B,操作B先行于操作C,那么操作A先行于操作C。
面试题
解释一下对象的创建过程
比如说我们要创建一个对象new T()第一步肯定是要把classloading到内存->第二步就是linking的过程,包括第三步
1:verification校验 2:preparation把类的静态变量设默认值 3:resolution做一个解析->接下来就是类的初始化把静态变量设为初始值同时执行静态语句块。创建对象然后需要申请内存,成员变量再赋默认值,然后调用构造方法在字节码层面,调用构造方法的时候,把成员变量设为初始值,接下来调用构造方法语句super调用父类。
#对象创建过程
1、class loading
2、class linking(verification,preparation,resolution)
3、class initializing
4、申请对象内存
5、成员变量赋默认值
6、调用构造方法<init>
1、成员变量顺序赋初始值
2、执行构造方法语句
对象在内存中的内存布局
作为对象的内存布局来将分为两种,第一种叫普通对象,第二种叫数组对象
#普通对象首先有
1:第一是对象头,在hotport里面称为markword长度是8个字节
2:第二个是ClassPointer指针:-XX:+UseCompressedClassPointers为4个字节不开启为8个字节
3:第三个是实例数据
1:引用类型:-XX:+UseCompressedOops为四个字节不开启为八个字节
Oops Ordinary Object Pointers
4:Padding对齐,这个对齐是8的倍数
普通对象样子,首先有一个对象头markword8个字节,第二个这个对象它是属于哪个class的,它有一个指针是ClassPoint指针,这个指针指向你要的class对象,接下来实例数据也就是加成员变量还有引用类型,第四个就是Padding对齐,主要是因为算出来正好是15个字节,但是作为64位机器,它是按块来读,不是按你的字节来读,它这里有一个对齐它是8的倍数。
#数组对象
1、对象头:markword 8
2、ClassPoint指针同上
3、数组长度:4字节
4、数组数据
5、对齐8的倍数
数组对象多了一项,第一个对象头一样,第二个ClassPoint你这个对象数组里装的是哪种类型的数据,第三个多了一个数组长度4个字节,第四个数组数据,第五个对齐8的倍数。
对象头具体包括什么
第一锁定信息两位代表对象有没有被锁定,第二个GC的标记他被回头多少次了分代年龄
对象怎么定位
对象定位有两种:1、句柄池 2、直接指针
就是当我们new出来一个对象T t = new T();这个小t是怎么找到对象的,有两种方式第一种是通过句柄池,通过间接指针,它只第一步把小t指向两个指针,这两个指针其中一个指向对象,另一个指向t.class,就是中间隔了一下
第二种直接指向对象然后在指向t.class,他两没有优劣之分,有的虚拟机实现用第一种有的用第二种,Hotspot用的是第二种,第二种效率比较高直接找到对象。
对象怎么分配
首先new一个对象的时候先往栈上分配,栈上如果能分配下就分配在栈上,然后栈一弹出对象就没了,如果栈上分配不下,特别大,直接分配到堆内存,老年代。
如果不大,首先会进行线程本地分配,线程本地分配能分配下就分配,分配不下找伊甸区然后进行GC的过程,GC过程年龄到了就直接到老年代了,如果年龄不到的话GC来GC去一直到年龄到了为止。