zoukankan      html  css  js  c++  java
  • 内存屏障与JVM指令

    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:主内存,写变量值
    

    1600505014855

    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去一直到年龄到了为止。
    
  • 相关阅读:
    Python调用C++的DLL
    Go-map
    Go-切片
    Go-数组
    Go-流程控制
    Go-运算符
    Go-变量和常量
    Go-VS Code配置Go语言开发环境
    Go-跨平台编译
    Go-从零开始搭建Go语言开发环境
  • 原文地址:https://www.cnblogs.com/striver20/p/13763535.html
Copyright © 2011-2022 走看看