面试 1:简述JVM的内存布局

1. 我的回答

  • JVM内存布局分两块:线程共享和非线程共享。线程共享区域有堆区、方法区;非线程共享区有程序计数器、方法栈、本地方法区。
  • 堆区:当对象被创建时,就在堆中开辟相应的内存空间,用来存储对象中的非静态成员变量,指向方法区的方法描述。这里是垃圾回收的区域。
  • 方法区:类的class字节码加载到此区域中,并开辟相应的静态空间。
  • 程序计数器:记录栈帧中方法执行的字节码指令的位置。
  • 方法栈:以栈帧为单位,每调用一个新的方法,就开辟一个栈帧,栈帧中存放的局部变量表,方法参数,本地方法等诸多信息。
  • 本地方法区:调用到了其他语言的代码。
    在这里插入图片描述

2. 满分回答

  • 堆区:是线程共享的区域(和java程序的生命周期相同)。java堆中用来存放实例对象以及数组对象。由于现在有了逃逸分析技术,也可以将对象分配在栈中。
    解释:逃逸分析技术是将对象在栈中分配的一种技术,因为栈空间相对堆空间较小,所以该对象一般是小对象。
    同时,java堆也是垃圾回收的主要区域,垃圾回收主要采取分代回收的方式,有年轻代,老年代,如下图。
    在这里插入图片描述
    java堆中是可以是物理上不连续的区域,只要逻辑上连续即可。在堆中分配内存的方法有:
    • 碰撞指针:在连续剩余空间中分配内存。用一个指针指向内存已用区和空闲区的分界点,需要分配新的内存时候,只需要将指针向空闲区移动相应的距离即可。
    • 空闲列表:在不规整的剩余空间中分配内存。如果剩余内存是不规整的,就需要用一个列表记录下哪些内存块是可用的,当需要分配内存的时候就需要在这个列表中查找,找到一个足够大的空间进行分配,然后在更新这个列表。
      注:分配的选择方式取决于采用的垃圾回收算法。指针碰撞的分配方式明显要优于空闲列表的方式,但是使用哪种方式取决于堆内存是否规整,而堆内存是否规整则由使用的垃圾收集算法决定。如果堆内存是规整的,则采用指针碰撞的方式分配内存,而如果堆是不规整的,就会采用空闲列表的方式。
      标记-清除算法:
      在这里插入图片描述
      标记-压缩算法:
      在这里插入图片描述
      对象访问方式有两种:句柄和直接访问
  • 方法区:与堆一样,是线程的共享区域。用于存储已经被虚拟机加载的类的信息、常量、静态变量、编译后的代码,运行时常量池。方法区中有一个运行时常量池,class文件中的常量池在类加载后就被放入运行时常量池。运行时常量池相对于class文件中的常量池,具有动态性。可以在运行期间通过intern将常量放入池中,方法区空间不足抛出outOfMemoryError,和堆一样。
  • 程序计数器:该区域是内存中较小的一块区域,是当前线程在执行的字节码的行号指示器。程序计数器是线程私有的,每个线程都有一个程序计数器,线程之间的程序计数器相互独立,互不干扰。是jvm规范中唯一一个没有规定任何outOfMemoryError情况的区域
  • 虚拟机栈:是线程私有的,其生命周期与线程相同。虚拟机描述的是java方法执行的内存模型,每个方法执行的时候,都会创建一个栈帧用于存储局部变量表,操作数栈、动态链接、方法出口信息。每个方法从调用结束就会有栈帧在虚拟机栈中入栈和出栈。一个方法的调用链可能会很长,于是当调用一个方法时,可能会有很多方法都处于执行状态,但对于执行引擎来讲,至于位于虚拟机栈顶的栈帧才是有效的,这个栈帧被称为当前的。StackOverFlowerror异常。
发布了106 篇原创文章 · 获赞 91 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/weixin_42512488/article/details/91357475
今日推荐