jvm 常见面试题 长期更新

1.1 举例栈溢出的情况

1.2 调整栈的大小,就能保证不出现溢出吗?

1.3 分配的栈内存越大越好吗?

1.4 垃圾回收是否会设计到虚拟机栈

1.5 方法中定义的局部变量是否线程安全 

2.1 堆是分配对象的唯一选择吗? 

2.2 永久代为什么要被元空间替换?

 2.3 说一下jvm内存模型有哪些,分别干什么的?

 2.4 jvm的内存分布/内存结构?堆和栈的区别?堆的结构?为什么两个servivor区?

 2.5 eden和survior的比例分配?

 2.6 jvm为什么要有新生代和老年代?

 2.7 jvm的永久代中会有垃圾回收吗?

 3.1 对象在jvm中是如何存储的?对象头中有什么内容?

 3.2 jvm是如何通过栈帧中的对象引用访问到其内部的对象实例的呢?

 4.1 常常看见变量和方法被 static 和 final 两个关键字修饰,为什么这么做?

 4.2 class类加载的过程

 5.1 synchronized和lock的区别





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");
    }
}
View Code

 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)

  由于类的元数据分配在本地内存中,元控件的最大可分配控件就是系统可用内存空间

  这项改动很有必要原因有:

    1. 为永久代设置空间大小是很难确定的. 某些场景下,如果动态加载类过多,容易产品Prem区的OOM,比如某个Web工程中,因为功能点比较多,在运行过程中,要不断动态加载很多类,经常出现知名错误,而元空间和永久代之间最大的区别在于,元空间并不在虚拟机中,而是直接使用本地内存,因此默认情况下,元空间的大小仅受本地内存的限制
    2. 对永久代就行调优是很困难的. 方法区的垃圾回收(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定位到对象实例

  对象访问的方式主要有两种

    1. 句柄访问:  
      1. 好处: reference中存储稳定句柄地址,对象被移动(垃圾收集时移动对象很普遍)时只会改变句柄中实例数据指针即可,reference本身不需要被修改
    2. 直接指针(Hotspot)采用  
      1. 好处: 可以直接访问到对象效率更高

 4.1 常常看见变量和方法被 static 和 final 两个关键字修饰,为什么这么做?

1. 变量和方法于类无关,可以直接使用,使用比较方便;
2. 强调变量内存地址不可变,方法不可继承覆写,强调了方法内部的稳定性
 

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的区别

  1. synchronized是关键字,而lock是一个接口
  2. synchronized会自动释放锁,lock需要手动释放锁
  3. synchronized是不可中断,lock可以中断也可以不中断
  4. 通过lock可以知道县城有没有拿到锁,而synchronized不能
  5. synchronized能锁住方法和代码块,lock只能锁住代码块
  6. lock可以使用读锁提高多线程的效率
  7. synchronized是非公平锁,reentrantLock可以控制是否为公平锁

 

 

 
原文地址:https://www.cnblogs.com/xiaodu9499/p/13264818.html