2.3 说一下jvm内存模型有哪些,分别干什么的?
2.4 jvm的内存分布/内存结构?堆和栈的区别?堆的结构?为什么两个servivor区?
2.5 eden和survior的比例分配?
2.6 jvm为什么要有新生代和老年代?
2.7 jvm的永久代中会有垃圾回收吗?
3.2 jvm是如何通过栈帧中的对象引用访问到其内部的对象实例的呢?
4.1 常常看见变量和方法被 static 和 final 两个关键字修饰,为什么这么做?
1.1 举例栈溢出的情况
StackOverflowError,不合理的递归容易造成栈溢出
1.2 调整栈的大小,就能保证不出现溢出吗?
可以减少出现的情况,但是不能保证栈不溢出
1.3 分配的栈内存越大越好吗?
理论上栈分配的越大越能避免出现栈溢出的情况,但是会挤占其他内存结构的空间
1.4 垃圾回收是否会设计到虚拟机栈
不会,虚拟机栈不存在GC,只存在出栈
1.5 方法中定义的局部变量是否线程安全
具体情况具体分析
public class StringBuilderTest { /** * 此方法为线程安全 */ public static void method1(){ // stringBuilder 线程不安全 StringBuilder s1 = new StringBuilder(); s1.append("a"); s1.append("b"); } /** * 此方法为线程不安全 */ public static void method2(StringBuilder s1){ // stringBuilder 线程不安全 s1.append("a"); s1.append("b"); } }
2.1 堆是分配对象的唯一选择吗?
来源 : https://www.bilibili.com/video/BV1PJ411n7xZ?p=82
在<<深入理解java虚拟机>>中关于java堆内存有这样一段描述: 随着jit编译器的发展与逃逸分析技术的逐渐成熟,栈上分配,标量替换优化技术将会导致一些微妙的变化,所有对象都分配到堆上也渐渐变得不那么绝对了.
在java虚拟机中,对象是在java堆中分配内存的,这是一个普遍的常识,但是有一种特殊情况,那就是 如果经过逃逸分析后发现,一个对象没有逃逸出方法的话,那么就可能被优化成栈上分配,这样就无需在堆上分配内存,也无需进行垃圾回收了,这也是常见的堆外存储技术.
此外,基于openjdk深度定制的TaoBaoVM,其中创新的GCIH(GC invisible heap)技术实现off-heap,将生命周期较长的java对象,从heap中移至heap外,并且gc不能管理gcih内部的java对象,一次达到降低gc的回收频率和提升gc回收效率的目的
2.2 永久代为什么要被元空间替换?
来源: https://www.bilibili.com/video/BV1PJ411n7xZ?p=98
随着java8的到来,hopspot vm中再也见不到永久代了,但是这并不意味着类的元数据信息也小时了,这些数据被移到了一个与堆不相连的本地内存区域,这个区域就叫元控件(Metaspace)
由于类的元数据分配在本地内存中,元控件的最大可分配控件就是系统可用内存空间
这项改动很有必要原因有:
- 为永久代设置空间大小是很难确定的. 某些场景下,如果动态加载类过多,容易产品Prem区的OOM,比如某个Web工程中,因为功能点比较多,在运行过程中,要不断动态加载很多类,经常出现知名错误,而元空间和永久代之间最大的区别在于,元空间并不在虚拟机中,而是直接使用本地内存,因此默认情况下,元空间的大小仅受本地内存的限制
- 对永久代就行调优是很困难的. 方法区的垃圾回收(full gc)主要回收两部分内容,常量池中废弃的常量和不在使用的类,在判断类是否在使用十分耗时,将方法区到元空间可以减少full gc
2.3 说一下jvm内存模型有哪些,分别干什么的?
2.4 jvm的内存分布/内存结构?堆和栈的区别?堆的结构?为什么两个servivor区?
2.5 eden和survior的比例分配?
2.6 jvm为什么要有新生代和老年代?
2.7 jvm的永久代中会有垃圾回收吗?
3.1 对象在jvm中是如何存储的?对象头中有什么内容?
https://www.cnblogs.com/xiaodu9499/p/13275956.html
3.2 jvm是如何通过栈帧中的对象引用访问到其内部的对象实例的呢?
局部变量会保存对象这对内存中的位置也就是对象的reference,通过栈上的对象reference定位到对象实例
对象访问的方式主要有两种
- 句柄访问:
- 好处: reference中存储稳定句柄地址,对象被移动(垃圾收集时移动对象很普遍)时只会改变句柄中实例数据指针即可,reference本身不需要被修改
- 直接指针(Hotspot)采用
- 好处: 可以直接访问到对象效率更高
- 句柄访问:
4.1 常常看见变量和方法被 static 和 final 两个关键字修饰,为什么这么做?
4.2 class类加载的过程
所谓类加载,简而言之就是讲java类的字节码文件加载到机器内存中,并在内存中构建出java类的原型-- 类模板对象,所谓类模板对象,其实就是java类在jvm内存中的快照,jvm将从字节码文件中解析出的常量池,类字段,类方法等信息存储到类模板中,这样jvm在运行期间便能通过类模板而获取java类中的任意信息,能够对java类的成员变量进行遍历,也能进行java方法的调用
4.3 class类文件结构
- 魔数与class文件的版本: class文件头的四个字节被称为魔数,他唯一的作用是确定这个文件是否为一个能否被虚拟机接受的calss文件,紧接着魔数的四个字节存储的事class文件的版本号,第5和第6个字节是次版本号,第7第8是主版本号
- 常量池: 常量池可以比喻为calss文件里的资源仓库,主要存放两大类常量: 字面量和符号引用,字面量比较接近于java语言层面的常量概念,如文本字符串,被声明为final的常量值等,而符号引用则属于便于原理方面的概念主要包括下面几类常量:被模块到处或者开放的包,类和接口的全限定名,字段的名称和描述符,方法的名称和描述符,方法句柄和方法类型,动态调用点和动态常量
- 访问标志: 用于标识一些类或者接口层次的访问信息,包括:这个class是类还是接口,是否定义为public类型,是否定义为abstact类型,如果是类的话,是否被声明为final类型等等
- 类索引,父类索引与接口索引集合: 用来确认该类型的继承关系
- 字段表集合: 用于标书接口中或者类中声明的变量
- 方法表集合: 描述了类中的方法,包括方法的访问标志,名称索引,描述符索引,属性表索引等
- 属性表集合:
5.1 synchronized和lock的区别
- synchronized是关键字,而lock是一个接口
- synchronized会自动释放锁,lock需要手动释放锁
- synchronized是不可中断,lock可以中断也可以不中断
- 通过lock可以知道县城有没有拿到锁,而synchronized不能
- synchronized能锁住方法和代码块,lock只能锁住代码块
- lock可以使用读锁提高多线程的效率
- synchronized是非公平锁,reentrantLock可以控制是否为公平锁