JVM入门概念

一个简单的汇编程序由指令和数据组成,编译为2进制机器码,人和机器都无法区分指令或是数据。

操作系统加载到内存后,通过约定的头部字节,配合特定的寄存器才能标识并正确的运行。

标识指令的寄存器有CS:IP;标识数据的寄存器有DS:XX;标识段寄存器有SS:SP。

如果当前代码遇到中断指令或跳转指令(函数地址),需要保留现场,执行完成之后还原现场。

C有跳转指令,更高级的是通过函数名或函数指针来调用子程序。

java指令到机器指令的转化是利用了函数指针来实现的。

 

java源代码(.java)被javac编译为字节码(.class),使用java命令加载到jvm中,

实施不同的内存区域管理,配合jvm指令,翻译到对应的机器码。jvm指令200多个。

 

jvm内存又称为Run-Time Data Area分为两类

1:线程共享区域(JVM启动时创建)(java没有类似c的free函数,需要垃圾收集器管理)

    1.1 java堆(java Heap)存放Object和数组。Xms初始堆空间,Xmx最大堆空间

    1.2 方法区(Method Area)别名非堆Non-Heap或永久区。存储java加载的类信息、常量、静态变量、方法字节码等等。

    1.3 直接内存(Direct Memory) 直接向OS申请的内存区域,速度优于Java堆。(NIO库使用直接内存)

2:线程私有区域(创建线程时创建)

    2.1 pc(program counter)寄存器,理解为类似CS:IP的jvm指令地址。如果执行native方法,值为Undefined。

    2.2 JVM Stack (jvm栈)和线程执行有关,Xss 线程栈空间。保存的数据结构称为栈帧(frame),由local variable(本地变量表)、operand stack(操作数栈)、runtime constant pool(运行时常量池,方法区)

    2.3 Native Method Stack(本地方法栈)别名C Stack

 

ClassFile结构如下: {

u4 magic; //魔数 0xCAFEBABE

u2 minor_version; //次版本号

u2 major_version; //主版本号 java8为52

u2 constant_pool_count;

cp_info constant_pool[constant_pool_count-1];

u2 access_flags; //指出class文件定义的是类还是接口,访问级别是public还是private,有18个种类

u2 this_class;  //常量池索引,类名,类似完全限定名(.换成/)

u2 super_class;   //常量池索引,超类名,类似完全限定名(.换成/)

u2 interfaces_count; //接口计数器,标识索引表的容量

u2 interfaces[interfaces_count]; //接口索引表

u2 fields_count;  //字段计数器

field_info fields[fields_count];  //字段表

u2 methods_count; //方法计数器

method_info methods[methods_count]; //方法表

u2 attributes_count;  //属性计数器

attribute_info attributes[attributes_count];  //属性表

}

总结:接口索引表、字段表、方法表、属性表都会指向常量池中的某项,常量池也会指向其某项。

可以通过工具查看

1:javap,自带的反编译工具   javap -p xxx.class 或 javap -p -v xxx.class

2:jclasslib https://github.com/ingokegel/jclasslib

3:classpy https://github.com/zxh0/classpy

 


字节码格式要变为本地机器码才能被执行,JVM通过以下步骤来实现这个变化。

加载---【验证---准备---解析(不一定)】(统称为linking)---初始化---使用---卸载

 

一、加载

1:通过类的全限定名来获取定义此类的二进制字节流(不一定是class文件)

2:将constant_pool转化为 方法区(Method Area)别名(非堆)Non-Heap或永久区的运行时数据结构

3:在java堆中生成一个代表这个类的java.lang.Class对象,作为方法区数据的访问入口

详细过程参考《java核心技术 卷二》第9章

参考:https://blog.csdn.net/briblue/article/details/54973413

 

二、验证 确保二进制节流包含的信息符合JVM的要求

1:文件格式验证

2:元数据验证(语义分析)

3:字节码验证(方法体校验分析)

4:符号引用验证(外连接是否正常)

 

三、准备

1:初始化类变量 static field 

2:初始化常量  static final

 

四、解析是将constant_pool内的符号引用替换为直接引用的过程。

符号引用理解为一个胖子,直接引用理解为13号(jvm中有上下文的具体目标)

如果没有13号呢?加载

 

五、初始化 执行类构造器clinit方法的过程。

1:clinit由static field和static{}块构成,如果类没有静态域或静态块,jvm可以不生成clinit方法,保证clinit线程安全。

2:clinit方法与类的构造函数<init>() 不同。构造函数在new时

3:父类的clinit方法先执行。

 

JVM内存分配过程

 

java类尚未被解析,直接进入慢分配。

如果没有开启栈上分配或不符合条件进行TLAB分配

TLAB的全称是Thread Local Allocation Buffer,即线程本地分配缓存区,这是一个线程专用的内存分配区域。

由于对象一般会分配在堆上,而堆是全局共享的。因此在同一时间,可能会有多个线程在堆上申请空间。因此,每次对象分配都必须要进行同步(虚拟机采用CAS配上失败重试的方式保证更新操作的原子性),而在竞争激烈的场合分配的效率又会进一步下降。JVM使用TLAB来避免多线程冲突,在给对象分配内存时,每个线程使用自己的TLAB,这样可以避免线程同步,提高了对象分配的效率。

TLAB本身占用eEden区空间,在开启TLAB的情况下,虚拟机会为每个Java线程分配一块TLAB空间。参数-XX:+UseTLAB开启TLAB,默认是开启的。TLAB空间的内存非常小,缺省情况下仅占有整个Eden空间的1%,当然可以通过选项-XX:TLABWasteTargetPercent设置TLAB空间所占用Eden空间的百分比大小。

如果TLAB分配不成功,尝试在eden区分配(新生代)

如果eden区分配失败,则进入慢分配流程

如果对象满足了直接进入老年代的条件,就直接分配在老年代

快速分配。对于热点代码,如果开启逃逸分析,JVM会执行栈上分配或标量替换等优化方案。

 

垃圾回收示意

在垃圾回收算法中,有一个算法称之为复制算法。其基本思想是把内存分为大小相等的2块,每次只在其中一块区域内进行内存分配,当发生GC时,将这块区域内存活的对象复制到另外一个区域内,然后对这块区域进行Full GC,这样可以保证内存的连续性,减少了空间碎片的产生.然后这种方式牺牲了一半的内存使用空间。Eden区与Survior区的概念也由此得来。

1、Eden区

Edeb区位于JVM中的新生代,是新对象分配内存的地方,由于堆是所有线程共享的,所以在堆上分配内存需要加锁。

而Sun JDK为了提升效率,会为每个新建的线程分配一个独立的内存区域,这块区域称之为TLAB(Thread Location Allocation

Buffer).在TLAB上分配内存是不需要进行加锁的,所以Eden区域的对象内存分配会优先在TLAB上进行.若是对象过大或者是TLAB的内存空间使用完,则对象的内存分配会在堆上进行。如果Eden区内存耗尽,则会触发Minor GC(Young GC)。

2、From Survivor和To Survivor区

针对新生代对象"朝夕生死"的特点,将新生代划分为3块区域u,分别为Eden、From Survior、ToSurvior,比例为8:1:1。

From和To是相对的,每次Eden和From发生Minor GC时,会将存活的对象复制到To区域,并清除内存。To区域内的对象每存活一次,它的"age"就会+1,当达到某个阈值(默认为15)时,ToSurvior区域内的对象就会被转移到老年代。

可以通过设置参数-XX:MaxTenuringThreshold来设置晋升的年龄。

虚拟机提供了一个参数:-XX  PertenureSizeThreshold 使得大于这个参数的对象直接在老年代中分配内存,这样就避免了在Eden区域以及Survior区域进行大量的内存复制。

3、老年代

老年代中是存活时间久的大对象(很长的字符串或者是数组),因此老年代使用标记-整理算法。当老年代容量满的时候,会触发一次MajorGC (FullGC)

---------------------

参考:https://blog.csdn.net/weixin_30300689/article/details/79888642

参考:http://www.cnblogs.com/QG-whz/p/9636366.html

参考《实战java虚拟机 jvm故障诊断与性能优化》

参考《深入理解java虚拟机 jvm高级特性与最佳实践》

参考《揭秘java虚拟机 jvm设计原理与实现》

参考《自己动手写jiava虚拟机》

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值