1.JVM内存结构和JMM的区别?
    JMM是表示线程与内存之间的关系,比如每个线程都有独立的工作内存,然后共享同一个主内存。
    JVM内存结构则是表示JVM由哪些部分组成,其内部的机构,包括的构成如下:

    1.类加载器
    类加载器的执行过程大致可以分为3个阶段——-加载、链接、初始化
    加载:就是给当前类选择一个合适的类加载器将其加载到内存中,这里就会用到一个双亲委派机制
    双亲委派机制:当某个类加载器要加载的时候,会首先去让找它的父类,看父类有没有加载过,如果没有就再网上,直到到达BootStrap,这个时候因为已经是最顶层了,BootStrap会尝试去加载,如果不成功则下沉到子加载器,一直到我们的自定义加载器,如果还是无法加载,就会抛出classNotFoundException。这也是为了安全着想,避免有人定义一个系统级别的类。

    链接:链接又可细分为3步
    校验:就是对字节码文件的格式进行校验,看是否合法
    准备:为类中的静态变量分配内存空间,并赋初始值。如果是staic finall修饰的,则会在这一步直接赋值。
    解析:将类中的符号引用转换为直接引用

    初始化:为静态变量赋值。在初始化该类之前会先看其父类有没有初始化,如果没有会去先初始化父类

    类加载器的分类:
    BootStrapClassLoader启动类加载器:JDK中的基础类库就是由它加载,就是lib文件夹下的
    ExtensionClassLoader扩展类加载器:JRE中的核心类库由它加载,就是lib\ext文件夹下的
    ApplicationClassLoader应用类加载器:加载classpath下的
    UserClassLoader:自定义类加载器

    2.运行时数据区
    线程私有的部分:

    程序计数器:程序计数器是线程私有的,它主要的作用是用来存储当前线程执行的当前方法的JVM指令地址,像是分支,循环,跳转,异常处理都要通过程序计数器来完成。而解释器也是通过修改计数器的值来确定下一条要执行的字节码指令。像是多线程,CPU需要来线程之间来回切换,计数器可以保证切换回来的时候知道从哪里开始继续执行。这也是唯一一个没有OOM的区域

    虚拟机栈:
    局部变量表:就是存储的方法形参和局部变量。
    操作数栈:方法中的所有字节码指令都存放在这里,它是遵循先入后出的规则,解释器就是基于操作数栈进行的。
    动态链接:class常量池中有大量的符号引用。其中一部分是在解析阶段转换为直接引用,这就是静态解析。其余的一部分是在运行时动态转换为直接引用,这就是动态链接。
    返回地址:方法的退出有两种方式,即正常退出和异常退出。
    当执行引擎遇到一个正常退出的字节码指令(retrun),会将返回值传递给上层的调用者,这就是正常退出。
    当方法执行中发生了错误,并在方法中没有进行处理,即在方法中的异常表中没有匹配到,就会造成异常退出。

    如果是有返回值,需要把返回值压入上层调用者的操作数栈中。

    本地方法栈:
    其实就跟虚拟机栈差不多,只不过这里存放的是native修饰的本地方法

    线程共享的部分:
    堆:存放对象、字符串常量池的地方
    堆的分类:(这仅仅是以前大部分垃圾收集器的划分方式,事实上像G1等收集器并没有划分新生代和老年代)新生代和老年代、新生代又分为Eden、From Survivor、To Survivor

    元空间:存放类信息、常量、静态变量、JIT编译后的代码以及运行时常量池。元空间和永久代都是堆JVM中方法区的实现,JDK1.8以前是永久代,以后是元空间。元空间使用的是本地内存。
    为什么要用元空间取代永久代?
    因为以前字串是存放在永久代中,很容易造成性能问题,所以后来将其移入了堆中。
    类和方法都比较难确定大小,所以永久代大小也不好确定,所以使用了元空间直接使用本地内存
    将HotSpot和JRockit合并。

    3.执行引擎
    分为解释器、JIT即时编译器、垃圾回收器GC
    解释器就是根据程序计数器一行一行的解释执行,当它发现一段代码是热点代码时会交给JIT,JIT将字节码编译成机器语言并加载到内存中,以后当执行到这段代码的时候都直接交给JIT执行,提高了效率。(比如循环等多次执行的)
    解释器启动快,执行慢。JIT启动慢,因为要编译,但是执行快。这也是为什么JVM选择解释器+JIT混合使用。

    4.本地方法库

    2.垃圾回收机制
    2.1 如何判断对象已死
    2.1.1 引用计数算法
    每当对象在一个地方被引用,计数器就加1,每当它失去一个引用,计数器就减1.只有当计数器为0的时候才认为它已死,才会通过GC回收它。
    这种算法的缺点在于,如果两个对象相互引用,那么就永远不会失去计数,也就永远回收不了。

    2.1.2 可达性分析算法
    垃圾回收器有一个起点,叫做GC Roots,将一个对象作为GC Roots,通过它发现其再也没有引用链的时候,也就是再也找不到其他引用它的对象,就认为已死,可以被回收。可以作为GC Roots的有:
    1.虚拟机栈中引用的对象
    2.方法区中静态变量引用的对象
    3.方法区中常量引用的对象
    4.JNI引用的对象

    2.2 垃圾回收算法
    2.3 什么时候回收垃圾
    2.4 垃圾回收器有哪些