java虚拟机(运行时数据区、内存中的对象)

Jdk And Jre

Jdk主要包括:
java程序设计语言
java虚拟机
java相关的一些api类库
jre主要包括:
java虚拟机
java SE的api子集

Sun HotSpot VM

这是一款最常见的虚拟机,是Sun Jdk和Open Jdk所带的虚拟机。
主要的核心技术:热点代码探测技术
可以通过执行计数器找出最具有编译价值的代码。如果一个方法被频繁的调用,或方法中有多次的循环调用,会触发标准编译和OSR编译动作。
还有其他的虚拟机
(Jam VM、Cacao VM、Sable VM、Kaffe、Jelatime JVM、Nano Vm、MRP、Moxie JVM、Jikes RVM)

java的发展方向

1.模块化
为了解决应用系统和技术平台越来越复杂、越来越庞大的问题的。在未来的Java平台中,很有可能会对模块化提出语法层面的支持,这是一种Java模块化的趋势。
2.多语言化
当单一的java开发无法满足软件的复杂需求时,越来越多的语言能基于java虚拟机开发。可以构思一下每种语言都有自己擅长的领域,不同的应用层分语言的开发。
3.多核并行
目前的主流是,cpu多核的模型,不再是单个cpu资源来回切换调度,而是一种多核并行的模式。

虚拟机模型区域

在这里插入图片描述

程序计数器

程序计数器首先是线程私有的,主要记录每个指令线程所执行的字节码的行号指示器。字节码解释器通过改变这这个计数器的值来选取下一条需要执行的字节码指令。分支、循环、跳转、异常处理、线程恢复都依赖这个计数器完成。
多线程的场景下,某个线程都需要记录当前执行的执行位置,因为资源的来回切换。

虚拟机栈

虚拟机栈也是线程私有的一块区域,主要存放了局部变量表、操作数栈、动态链接、方法出口等信息内容,记录的是每个方法从调用开始一直到完成的这个过程,伴随着出入栈。
栈溢出一般分为两种异常
StackOverFlowError:因为方法调用层数过大,既有可能递归导致的栈溢出。
OutOfMemoryError:可以设定每个栈的大小,这里是因为新的线程进来,给他申请内存的时候,出现不够导致的错误。

本地方法栈

本地方法栈也是线程私有的方法,和上面的差别主要体现在本地方法栈主要记录的native修饰的方法。
也有可能发生内存溢出。

内存堆

堆主要存放了所有的实例对象的信息,还有一些数组实例。堆内存是Jvm关注的区域,因为对象朝生夕死的特性,运行中需要进行大量的创建和回收,为此特意分了老年代和新生代,不同的区域做不同的回收策略。
堆是一块极易发生内存溢出的区域,主要要分析两种内存溢出的场景,改对象是否因为被回收而没有回收导致的?或者改对象不可回收但是过大的情况是否应该分配更大的内存?区分内存泄漏还是内存不够

方法区

方法区存储的主要是虚拟机加载进来的类信息、常量、静态变量这些内容。发生内存溢出的大部分的情况是因为,申请开辟一块内存被告诉内存不够了。

常量池

常量池主要存放了编译过程中,各种字面量和符号引用,发生溢出的条件和方法区相似。

直接内存

直接内存,不属于Jvm申请的内存空间。主要的场景有一些直接操作内存的NIO,会直接操作系统的内存,当然也会遇到系统内存不够的报错信息。

对象的创建

哪些方式

new
A a = new A()的方式,直接通过构造方法构建对象。
clone
a.clone()的方式创建对象,通过该类先实现Cloneable接口,重写clone方法实现。
serializable
通过该类实现serializable接口,标记该类可以被序列化和反序列化,通过字节流的方法创建对象
reflection
通过Class反射的方式,获取某个实例的方法,进行创建对象

指令创建过程

在这里插入图片描述
1.类加载过程之后讨论
2.给某个对象分配地址会遇到一些问题,如果堆内存是规整的,那么从空闲的空间,划一块区域给该对象,这种方式称为指针碰撞。另外从维护一个哪些区域那些内存还在空闲的列表,从里面找到一块内存填从,容易出现碎片多。
多线程在分配内存的会遇到同时对某块区域处理。
方案一采用同步的方案的,也就是通过CAS的方案分配内存,如果失败了再试的机制
方法二按照不同的线程,分内存块处理,预先为每个线程都分配了一小块缓冲,称为本地线程缓冲(Thread Local Allocation Buffer)。那个线程需要内存,都有用TLAB中获取,只有出现TLAB不够继续申请的情况下会加锁。
3.内存空间初始化零值,保证程序能访问到对象的实例字段和数据类型。
4.具体对对象进行必要的设置,该对象是那个类的实例,如何找到类的元数据,对象的哈希码,对象的GC分代年龄,主要是对对象头的设置,根据虚拟机当前的设置,是否开启偏向锁等内容
5.执行init方法,也就是你传进来的参数,如何对这个对象体进行一个赋值

对象的内存布局

对象头:
HotSpot虚拟机对象头MarkWord

存储内容标志位状态
对象的哈希码、对象的分代年龄01未锁定
指向锁记录的指针00轻量级锁定
指向重量级锁的指针01重量级锁定
空,不需要记录信息11GC标记
偏向线程ID、偏向时间戳、对象分代年龄01可偏向

对象头的另一部分是类型指针,指向元数据指针。通过该指针确认是某个类的对象,并不是所有的虚拟机实现都必须在对象数据上保留类型指针,换句话说,查找对象元数据不一定要通过对象本身。如果对象是一个数组,那么对象头还需要一块用于记录长度的数据。
对象实例数据:
真正存放对象的有效数据,也就是自定义的字段内容。无论是从父类继承下来的还是子类中定义的,这部分的存储顺序会受到虚拟机分配策略参数的影响。HotSpot默认的分配策略为longs/doubles、ints、shorts/chars、bytes/booleans、oops,依据这些分配策略我们可以看出,相同宽度的字段总是分配到一起。满足这些条件下,在父类中定义的变量会出现在子类之前。如果CompactFields是true会出现子类中较窄的变量,会插入父类变量中
对齐补充:
只是为了补全8的字节的整数倍。

对象的访问定位

句柄访问
有专门的句柄池

直接访问
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值