JVM总结(一)


jvm是运行在用户空间的虚拟计算机,是一种跨语言的平台;任何符合jvm规范的class文件都可以在平台上运行,与是否是java语言无关。以下主要从java语言的角度总结。

JVM基础知识

JVM/JRE/JDK

  • jvm ,java的运行平台
  • jre,jvm + core lib,是java语言的运行环境
  • jdk,jre + development kit,java的开发工具

常见的JVM

常见的jvm有oracle官方的Hotspot,BEA的Jrockit,现已被oracle收购,现在的Hotspot是原Hotspot与Jrockit的组合版;还有IBM的J9,微软的Microsoft VM,Hotspot的深度定制版TaobaoVM等。

Java的执行过程

在这里插入图片描述
类加载器class Loader 有两种模式,字节码解释器,JTL即时编译器。

class 的生命周期(class cycle)

jvm中一个class 通过了 loading --> linking --> initializing -->gc 的过程完成了一次生命周期。
而linking中又分为三步Verification Preparation Resolution。

loading

class文件被class loader 加载到内存以后,class的对象,指向class类的文件。

类加载器的种类

  1. BootStrap,是引导类加载器,加载核心类,是用c++实现的,通过xxx.class.getClassLoader()返回的是null。

  2. Extension,是扩展类加载器,加载扩展jar包。

  3. App,是系统类加载器,加载classpath指定的内容。

  4. CustomClassLoader,自定义的类加载器,由client自定义classloader。

     类加载器自1-4不是继承关系,自上而下是父加载器,不是类加载器的加载器,也不是类加载器的父加载器。
    

类加载机制(双亲委派机制)

  1. 加载过程:
    先find in cache,若未返回结果,再find各自维护的class list ,并加载
  2. 为什么使用双亲委派机制?
    主要是出于安全考虑的,避免核心的API被篡改,也可以避免类的重复加载。
  3. classLoader代码执行过程
    加载类时调用loadclass方法,先查询cache,若加载过就不会再重新加载,是在此方法中实现的双亲委派机制,要打破双亲委派机制,需重写loadclass方法,在jdk1.2之前,还有tomact热启动/热部署中,双亲委派机制被打破过。
    查询cache中未返回结果,再执行findClass方法,在class list中查找并加载。若要自定义classLoader,只需要extends ClassLoader,然后重写findclass方法即可,这是采用模板方法的设计模式实现的。
  4. 执行模式
执行模式参数设置说明
混合模式-Xmixed开始时时解释执行,启动很快,热点代码实行检测和编译
解释器模式-Xint启动快,执行稍慢
纯编译模式-XComp启动慢,执行快

热点代码是指,多次被调用的方法,多次被调用的循环,检测热带你代码的方法,

-XX:CompileThreshold = 10000

linking

  1. Verification
    校验文件是否符合jvm规范
  2. Preparation
    class文件的静态成员变量赋值为默认值
  3. Resolution
    解析,将类/方法/属性等符号引用解析为直接引用

initializing

静态成员变量赋值为初始值。

小结

对象的创建过程:
在这里插入图片描述

JMM(java内存模型)

java内存模型的全称时java memory model。

硬件层数据一致性

英特尔(intel)采用缓存一致性协议(MESI),数据一致性是通过缓存锁和总线锁来实现的。

缓存锁

读取缓存的基本单位是缓存行(cache line),经过工业实验,cache line的一般是64字节(bytes)。若同一缓存行的两个不同数据被不同的CPU锁定是,改变其中任何一个都要触发另外一个同步,会降低效率,这种现象被称为伪共享;要提高伪共享的效率,可在数据前后添加long型的变量实现对齐,称为缓存行对齐。例如:disrupt就采用了这种方式。

总线锁

对于某些无法缓存的数据,或者跨越多个缓存行的数据,不能用缓存锁,需要用总线锁来实现数据的一致性。

乱序问题

乱序问题是cpu为了提高执行效率采取的一种策略,不是真正意义上的乱序。

  1. 读乱序
    CPU的速度至少比内存快100倍,为了提升效率,会打乱原来的执行效率,会在一条指令执行过程中(比如去内存读数据,大概慢100多倍),去同时执行另一条指令,前提是两条指令没有依赖关系(洗茶壶/烧水-茶叶入壶-煮茶-喝茶)。洗茶壶/烧水两个步骤就没有依赖关系,可以同时进行。

  2. 写合并
    WC Buffer(Write Combining Buffer)一般是4个字节,比L1缓存快,由于ALU速度太快,为了提高写效率,CPU在写入L1时,写入一个WC Buffer,当WC Buffer满了之后,直接用WC写入L2。

  3. 有序性保障

    3.1 X86 CPU级别
    cpu级别是通过内存屏障原子指令来保障有序性。

    3.1.1 不同类型的cpu,内存屏障的实现不同,intel cpu比较简单,有以下3种:
    3.1.1.1 sfence,写屏障指令,也就是save fence。在sfence指令前的写操作必须在sfence指令后的写操作前完成,即屏障两端的写操作不乱序。
    3.1.1.2 lfence,读屏障指令,也就是load fence。在lfence指令前的读操作必须在lfence指令后的读操作前完成,即屏障俩高端的读操作不乱序。
    3.1.1.3 mfence,读写屏障,在mfence指令前得读写操作必须在mfence指令后的读写操作前完成,屏障前后的读写操作不乱序。
    3.1.2 原子指令,lock,执行lock指令时会锁住内存子系统,来确保执行顺序

    3.2 JVM级别规范
    3.2.1 jvm级别的内存屏障有以下4种:
    LoadLoad,StoreStore,LoadStore,StoreLoad;例如:load1 LoadLoad load2,load2及后续的读操作要读取的数据被访问之前需要确保已经被load1读取完毕。
    3.2.2 jvm指令的重排序需要遵守8条规则,即happens-before原则。但是,无论怎么重排序,最后的执行结果是不变的(as is serial)。
    3.2.3 volatile 实现细节
    ① 字节码层面
    加了ACC_VOLATILE的标志
    ② JVM层面
    对volatile内存区的读写都加了内存屏障

     	StoreStoreBarrier
     	volatile写操作
     	StoreLoadBarrie
     	
     	LoadLoadBarrier
     	volatile读操作
     	LoadStoreBarrier
    

    ③ OS和硬件层面
    用windows的lock指令实现
    3.2.4 synchronized 实现细节
    ① 字节码层面
    synchronized void m(){} 添加 ACC_SYNCHRONIZED 标记
    void n(){synchronized(this){}} 用monitorenter monitorexit实现
    ② JVM层面
    C C++ 调用了操作系统提供的同步机制
    ③ OS和硬件层面

lock compxch /xxx #lock 后面执行的内存修改,其他CPU无法操作

对象在内存中的存储布局

在这里插入图片描述

  1. mark word 的分布如下图:
    在这里插入图片描述
    在这里插入图片描述
    由图可以得知:分代年龄最大位15;对象在无锁状态时的hashcode位原始hashcode,被重写过后,原始hashcode将不会再存在。
  2. Class Pointer
    指向class文件的指针
	-XX:+UseCompressedClassPointers 	#开启压缩(默认),4字节
    -XX:-UseCompressedClassPointers 		#不开启压缩,8字节
  1. 实例数据(instance data),其中数组长度占4字节,普通对象中,指向普通对象的指针Oops(Ordinary Object Pointers),在开启压缩的情况下占4字节,不开启占8字节,设置参数为-XX:+UseCompressedOops
  2. Padding对齐,对象的总长度与8的倍数对齐,若是8的倍数,则没有Padding,若不是8的倍数,用Padding补齐。
  3. Hotspot 开启内存压缩的规则
内存大小压缩规则
<4G直接砍掉高32位
4G-32G默认开启内存压缩Oops
>4G压缩无效,直接使用64位

由此可见,内存不是越大越好。
6. 对象定位(访问对象的方式)

  • 句柄池,java堆区划分一块内存作为句柄池,对象被移动时,只会改变句柄中实例数据的指针,比较稳定。
  • 直接指针,速度快,节省了一次指针定位的时间开销,Hotspot采用此种方式访问对象。
    具体描述可参照句柄池/直接指针详细介绍

运行时数据区和指令集

运行时数据区(JavaRuntime Data Area)

线程共享区域随VM启动存在,线程私有区域随线程启动存在

  1. 程序计数器,存放指令位置,在VM运行的过程中,循环执行取指令/执行指令,计数器++的操作(取出PC中的位置,然后找到对应位置的指令,执行,执行完之后PC++)。
  2. jvm stack,每个方法在执行的同时都会创建一个栈帧(Frame),存储本地变量表(Local Variable Table),操作数栈(Operand Stack),动态链接(Dynamic Liniking),方法出口(return address)等信息。
    本地变量表相当于jvm中的寄存器,存放基本数据类型,boolean/byte/char/short/int/float/long/double/对象引用,long和double是64位的,占用2个本地变量表空间,其余类型的占用一个;对于static method(){},存放的是参数和变量等信息,对于非static方法,第0个位置是this,第一个开始是参数/变量等信息。
    操作数栈,是在方法执行过程中的压栈(load)/弹栈(store)操作。
    动态链接,寻找常量池中找到真的value(class文件格式)
    方法出口,例如:A方法调用了B方法,B方法返回值就在方法出口中。
  3. 本地方法栈,与vm栈相似,vm栈是位java方法服务的,native method stack 是为本地方法服务的。
  4. ,又称为GC堆,是垃圾回收器管理的主要区域,存放的是java对象实例,在GC中详细讲解。
  5. 方法区,主要存放的是jvm加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。在jdk1.8之前,方法区又称为Permanent Space(永久代),字符串常量位于Permanent Space,FGC不会被清理,大小在启动的时候已经被指定,不能改变;在jdk1.8之后,被称为Meta Space(元数据区),字符串常量位于Heap,会触发FGC清理,若不设定大小,最大是物理内存。

指令集(InstructionSet)

指令集分为基于寄存器的指令集,和基于栈的指令集,Hospot是基于栈的指令集。
常用的指令有,store(弹栈),load(压栈),mul(乘法),sub(减法);invoke_xxx(方法调用),如InvokeStatic(调用静态方法),InvokeSpecial(调用private方法),InvokeInterface(调用接口)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值