JVM知识点(二)运行时数据区

运行时数据区

运行时数据区内部结构

在这里插入图片描述

程序计数器

程序计数器(也叫PC寄存器):寄存器存储指令相关的现场信息,cpu只有把数据装载到寄存器才能运行。jvm中的pc寄存器是对物理pc寄存器的一种抽象模拟。pc寄存器用来存储指向下一条指令的地址,也即将要执行的指令代码,由执行引擎读取下一条指令。

常见面试题
  1.为什么要使用pc寄存器记录当前的线程执行地址呢?使用pc寄存器存储字节码指令地址有什么用?
  答:因为cpu需要不停的切换各个线程,这时候切换回来以后就需要知道从哪里继续执行。JVM字节码解释器就需要通过改变pc寄存器的值来明确下一条应该执行什么样的字节码指令。
 2.pc寄存器为什么被设定为线程私有?
  答:由于cpu会不停的做任务切换,这样必然会导致经常中断或恢复,为了能够准确的记录各个线程正在执行的当前字节码指令地址,最好的办法就是为每一个线程都分配一个pc寄存器,这样一来各个线程之间可以独立计算,互不干扰。


虚拟机栈

 虚拟机栈出现的背景:由于跨平台性的设计,java指令都是根据栈来设计的,不同平台cpu架构不同,所以不能设计为基于寄存器的。他的优点是跨平台,指令集小,编译器容易实现,缺点是性能下降,实现同样的功能需要更多指令。

什么是java虚拟机栈?
  java虚拟机栈,早期也叫java栈,每个线程在创建时,都会创建一个java虚拟机栈,其内部保存一个个栈帧对应着一次次的方法调用,他是线程私有的。
  jvm直接对栈的操作只有两个,就是对栈帧的压栈和出栈,遵循“先进后出,后进先出”原则
  虚拟机栈的生命周期和线程一致。
  作用:主管java程序的运行,他保存方法的局部变量,部分结果,并参与方法的调用和返回。
栈中存储的是什么?
1.每个线程都有自己的栈,栈中的数据都是以栈帧的格式存在的
2.在这个线程上每一个正在执行的方法都对应一个栈帧
3.栈帧是一个内存区块,是一个数据集,维系方法执行中的各种数据信息。
栈帧中的内部结构

  • 局部变量表(栈中调优 和局部变量表有关)
  • 操作数栈
  • 动态链接(或运行时常量池的引用)
  • 方法返回地址(或方法正常退出或者异常退出的定义)
  • 一些附加信息

栈中存常见异常
    Java虚拟机允许栈的大小是固定的或者是动态变化的,当虚拟机栈容量固定不变时,如果线程请求分配的栈容量超过java虚拟机栈允许的最大容量,java虚拟机会抛出StackOverflowError异常,如果栈是可以动态扩展的在尝试扩展时无法申请到足够的内存,或者在创建新的线程时没有足够的内存去创建对应的虚拟机栈,那么虚拟机会抛出OutOfMemoryError异常。

栈顶缓存技术
由于操作数是存储在内存当中的,因此频繁的执行内存的读写操作必然会影响执行速度。而栈顶缓存技术就是将栈顶元素全部缓存在物理cpu的寄存器中,降低读写次数,提高执行引擎的执行效率。


虚拟机栈常见面试题

  1. 举例栈溢出的情况?
    答:StackOverflowError和OutOfMemoryError

  2. 调整栈大小就能保证不出现溢出么?
    答:不能

  3. 分配的栈内存越大越好么?
    答:不是,会挤占其他内存空间

  4. 垃圾回收是否会设计到虚拟机栈?
    答:不会,只会涉及到堆和方法去

  5. 方法中定义的局部变量是否线程安全?
    答:具体情况具体分析,得看这个数据是被单个还是多个线程操作,单线程操作时安全的,多线程操作不考虑同步机制问题会存在线程安全问题。

本地方法栈

  • java虚拟机栈用来管理java方法的调用,而本地方法栈用于管理本地方法的调用。
  • 本地方法栈也是线程私有
  • 允许被实现成固定或者时可拓展的内存大小
  • 本地方法时C语言实现的
  • 具体做法是在虚拟机栈中登记本地方法,在Execution Engine执行时加载本地方法库。

堆的核心概述
  • 一个jvm实例只存在一个堆内存,堆也是java内存管理的核心区域
  • java堆区在jvm启动时就被创建,其空间大小也被确定,是jvm管理的最大的一块内存空间。
    – 堆内存的大小是可以调节的
  • java虚拟机规范规定,堆可以处于物理上不连续的内存空间中,但在逻辑上他应该被视为连续的
  • 所有的线程共享java堆,在这里还可以划分线程私有的缓冲区
  • 所有的对象实例以及数组都应当在运行时分配到堆上
  • 数组和对象可能永远不会存储在栈上,因为栈帧中保存引用,这个引用指向对象或者数组在堆中的位置。
  • 在方法结束后,堆中的对象不会马上被移除,仅仅在垃圾收集的时候被移除
  • 堆,是GC(垃圾收集器)执行垃圾回收的重点区域
堆中内存结构

jdk1.7及之前 年轻代 老年代 永久区
jdk1.8及之后 年轻代 老年代 元空间

设置堆内存大小和OOM

堆空间大小的设置

  • java堆区用于存储java对象实例,那么堆的大小在jvm启动时已经设定好了,可以通过选项 -Xmx(最大内存)和 -Xms(起始内存) 来进行设定
  • 一旦堆中的内存大小超过-Xmx指定的最大内存时,将会抛出OOM异常
  • 通常会将 -Xmx 和 -Xms 这两个参数设置为相同的值,其目的时为了能够在java垃圾回收机制清理完堆区后不需要重新分隔计算堆的大小,从而提高性能。
  • 默认情况下,初始内存大小为物理电脑内存大小的64分之一,最大内存为物理电脑内存大小的4分之一。
Minor GC ,Major GC, Full Gc的区别

jvm在进行GC时,并非每次都对上面三个内存(新生代,老年代;方法区)区域一起回收的,大部分时候回收都是指新生代
针对HotSpot VM的实现,它里面的GC 按照回收区域又分为两大种类型:一种是部分收集(Partial GC),一种是整堆收集(Full GC):

  • 部分收集:不是完整收集整个java堆的垃圾收集。其中又分为:
    – 新生代收集(Minor GC / Young GC):只是新生代的垃圾收集
    – 老年代收集(Major GC / Old GC):只是老年代的垃圾收集。
    注意1.目前只有CMS GC会有单独收集老年代的行为。2. 很多时候Major GC会和Full GC混淆使用,需要具体分辨是老年代回收还是整堆回收。
    –混合收集(Mixed GC):收集整个新生代以及部分老年代的垃圾收集(目前只有G1 GC 会有这种行为)
  • 整堆收集(Full GC):收集整个java堆和方法区的垃圾收集。

方法区

  • 方法区和堆一样,是各个线程共享的内存区域
  • 方法区在jvm启动时被创建,并且他的实际的物理内存空间中和java堆区一样都可以不连续的。
  • 方法区的大小跟堆空间一样,可以选择固定大小或者可拓展
  • 方法区的大小决定了系统可以保存多少个类,如果系统定义了太多的类,导致方法区溢出,虚拟机同样会抛出内存溢出错误
  • 关闭jvm就会释放这个区域的内存。

方法区存储的是什么?
它用于存储已被虚拟机加载的类型信息,常量,静态变量,即时编译器编译后的代码缓存等。
方法区的垃圾回收主要分为两部分内容:常量池中废弃的常量和不在使用的类型

常见面试题
百度:说一下jvm内存模型,有哪些区,分别是做什么的?
蚂蚁金服:java8的内存分代改进,jvm内存分几个区,每个区的作用是什么?

  • 一面:jvm内存结构,栈和堆的区别,堆的结构,为什么有两个survior区?
  • 二面:eden和survior的比例分配

小米:jvm内存分区,为什么要有新生代和老年代
字节跳动:讲讲jvm运行时数据库区,什么时候对象会进入老年代
京东:jvm内存为什么要分为新生代老年代和持久代。新生代中为什么要分eden和survior区
天猫:jvm内存模型,java8以后做了什么修改
美团:jvm永久代中会发生垃圾回收么?

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值