深入理解java虚拟机笔记-第2章 java内存区域与内存异常

2 java内存区域与内存溢出异常

2.2 运行时数据区域

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2OSWsIQ1-1578474655652)(D6547E73F7084A8EAA70A8A582288F53)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sYTRboLe-1578474655654)(51255909AE6448349BA5A5E538492F1E)]

2.2.1 程序计数器(Program Counter Register)

相当于当前线程所执行字节码的行号解释器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。

虚拟机的多线程是通过线程轮流切换,分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器都只会执行一条线程中的指令。 各条线层之间计数器互不影响,独立存储,我们称这类内存区域为线程私有的内存。
此区域是唯一个没有OutOfMemoryError情况的区域。

2.2.2 java虚拟机栈(Java Virtual Machine Stack)

虚拟机栈描述的是Java方法执行的线程内存模型:每个方法被执行的时候,java虚拟机都会同步创建一个栈帧 用于存储局部变量表、操作数栈、动态连接、方法出口
可能存在2中异常:

  1. 如果线程请求的栈深度大于虚拟机所允许的深度,将抛出栈溢出异常StackOverflowError。
  2. 如果java虚拟机栈容量可以动扩展,如果扩展的时候无法申请到足够的内存会抛出OutOfMemoryError异常。

操作数栈是一个后入先出栈,其最大深度也是在Code属性中已经确定了的(编译时期确定)。当执行字节码指令时,各种数据类型都会加载到操作数栈中。32位数据数据类型站1个栈容量,64位数据站2个栈容量。虚拟机实现会做一些优化。将两个操作数栈重叠一部分区域,省去额外的参数复制传递。

由于栈帧是用于方法调用和方法执行的数据结构。所以每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用。在class文件的常量池中有大量的符号引号。这些符号引用有一部分在类加载阶段或者第一次使用的时候就直接转化为直接引用(静态解析)。有的则在每一次运行期间转化为直接引用(动态连接)。

方法退出的方式有两种:正常完成出口和异常完成出口。其中正常完成可能会返回值(是否有返回值和返回值的类型由返回指令决定)。但是异常完成是没有返回值的。
但是无论怎么执行。方法退出后都需要要返回到方法被调用的位置。这样程序才能继续执行。所以方法返回时需要在栈帧中保存一些信息,用来恢复它上层方法的执行状态。
方法在退出,返回到上层方法执行操作有:恢复上层方法的局部变量表和操作数栈,把返回值(如果有)压入到调用者栈帧的操作数栈中。调整pc计数器的值。

2.2.3 本地方法栈(Native Method Stacks)

和虚拟机栈一样,只不过他是使用native调用的本地方法,所以存在的异常也和java虚拟机栈是一致的

2.2.4 java堆

线程共享区域,所有的对象实例以技术组都应当在堆上分配,但随着编译技术的进步
逃逸分析栈上分配标量替换 java对象实例都分配在对上也变的不是那么绝对了。

如果从分配内存的角度看,所有线程共享的java堆中可以划分出多个线程私有分配缓冲区
(Thread Local Allocation Buffer,TLAB),以提升对象分配时的效率。

堆在物理上是不连续的(数组则都是连续的),但是在逻辑上是连续,

-Xmx 用来设置你的应用程序(不是JVM)能够使用的最大内存数,如果你的程序要花很大内存的话,那就需要修改缺省的设置,比如配置tomcat的时候,如果流量啊程序啊都很大的话就需要加大这个值了,BUT不要大得超过你的机器的内存.

-Xms 用来设置程序初始化的时候内存栈的大小,增加这个值的话你的程序的启动性能会得到提高。不过同样有前面的限制,以及受到-Xmx的限制。

通常是设置成一样的大小来避免扩容所来带的系统开销。

2.2.5 方法区

线程共享区域,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码缓存等数据

2.2.6 运行时常量池

运行时常量池是方法区的一部分。用于存放编译期生成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行常量池中。运行期间也可以将新的常量放入池中,这种特性被开发人员利用较多的便是String类的intern() 方法。

字面量:int i = 1;把整数1赋值给int型变量i,整数1就是Java字面量

符号引用:org.simple.People类引用了org.simple.Language类, 在编译时People类并不知道Language类的实际内存地址, 因此只能使用符号org.simple.Language来表示Language类的地址.

直接指向目标的指针.(个人理解为: 指向方法区中类对象, 类变量和类方法的指针)

相对偏移量. (指向实例的变量, 方法的指针)

一个间接定位到对象的句柄.

2.2.6 直接内存

就是虚拟机外的内存,主要是jdk1.4加入了nio ,它可以使用Native函数库直接分配对外内存,然后通过一个存储在java堆里面的DirectByteBuffer对象作为这块内存的引用进行操作,如果超过了物理机内存,有也会出现OutOfMemoryError

2.3 HotSpot 虚拟机对象探秘

2.3.1 对象的创建

只是普通java对象, 不是 复制和反序列化创建的对象,只是new关键字创建的对象。

  1. 是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否被加载。
  2. 为新生对象分配内存。“指针碰撞” 和“空闲列表”方法来分配

指针碰撞并不是线程安全的,为了保证线程安全,有2种方法可以处理
方法1 : 一种是对分配内存空间的动作进行同步处理–实际上虚拟机是采用cas配上失败重试的方法保证更新操作的原子性;

方法2: 即 每个线程在java堆中预先分配一小块内存,称为本地线程分配缓冲(TLAB),那个线程要分配内存,就在那个线程的额本地缓冲区分配,只有本地缓冲区用完了,分配 新的缓存区时才需要同步锁定。虚拟机是否使用TLAB,可以通过-XX:+/-UseTLAB参数来设定。

  1. 初始化:不管是对象还是值都初始化默认值,虚拟机必须将分配到的内存空间(但不包含对象头)

  2. 设置对象头:对象头包括, 那个类的实例、如何才能找到类的元数据信息、对象的哈希吗、对象的GC分代年龄等信息。

5.对象内存模型已经完了,但是对于程序来说,对象才刚开始,然后要做就是执行构造函数 通过new 关键字的地方同时生成2条字节码指令。但如果直接通过其他方式产生的则不一定如此。new 指令完了会执行 初始化方法,然后对象才算被构造出来。

2.3.2 对象的内存布局

  • 第一部分: 对象头(header)

对象头分为2类信息, 第一类是用于存储对象自身的运行时数据,如哈希码,GC分代年龄、锁状态标识、线程持有的锁、偏向线程ID。
另外一部分是类型指针,及对象指向它的类型元数据的指针,java虚拟机通过这个指针来去顶该对象是那个类的实例。

  • 第二部分: 实例数据(Instance Data)

存储真正的实例数据
–XX:FieldsAllocationStyle参数
+XX:CompactFields 参数值为true

  • 第三部分: 对齐填充(Padding)

没有任何意义,只是补齐位数,任何对象的大小,都必须是8字节的整数倍

2.3.2 对象的访问定位

  • 使用句柄

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ud9dFPM0-1578474655655)(3316703803E64CBA83018B040E727AFC)]
栈中reference句柄对应的是堆中 句柄池里面的某一个地址,这个地址存放是 对象实例的内存地址信息。

优势:reference中存储的是稳定句柄地址,在对象被移动(垃圾收集时移动对象是非常普遍的行为)时 只会改变句柄中的实例数据指针,而reference本身不需要被修改。

  • 直接指针
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-puypPlXL-1578474655656)(E9FC3427A72C4515A1556D6A693E682C)]
    栈中reference直接存储的是实例对象的内存地址,但是在这个内存还会存对象类型的指针直接指向方法区。好处如果只是访问对象的话,就不需要多一次间接访问的开销。

2.4 实战

jdk8 以后没有永久代,元空间作为其他带者登场。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值