面试_java_Java内存区域(运行时数据区域)

128 阅读5分钟

虚拟机栈、程序计数器、Heap、本地方法栈、Metaspace属于JVM运行时的内存;按是否线程共享则可以分两类:堆和MetasSpace元空间属于线程共享的;虚拟机栈和本地方法栈、程序计数器是线程私有的

首先需要强调,Java 内存区域和内存模型是不一样的东西,内存区域是指 Jvm 运行时将数据分区域存储,强调对内存空间的划分。而内存模型( JMM )是定义了线程和主内存之间的抽象关系,也就是计算机内存(RAM)中的工作方式。


Java 内存区域由五部分组成:程序计数器、虚拟机栈、本地方法栈、Heap、方法区;前三个是线程私有的,后两个是线程共享的。




程序计数器

它主要存储的是当前线程所执行的字节码的行号等信息,字节码解释器据此来选取下一条字节码指令。每条线程都有一个独立的程序计数器,它是线程私有的。



虚拟机栈

虚拟机栈就是我们平常讲JVM内存堆栈中的栈。虚拟机为每一个线程创建一个虚拟机栈,线程私有,与线程的生命周期相同。程序中的每个方法在执行的时候都会在虚拟机栈中创建一个栈帧,里面存放了局部变量表、操作栈、动态连接、方法出口信息。方法结束后栈帧弹出,其中的内容随之销毁。

  1. 局部变量表,对应方法参数与局部变量,其类型是Java的8种基本数据类型加上对象引用。注意是对象的引用,不是对象本身。
  2. 操作栈,线程执行方法内部字节码操作指令时使用的后入先出栈,各种指令会往操作栈中写入和提取信息。Java虚拟机的解释执行引擎被称为“基于栈的执行引擎”,里面的“栈”就是操作栈。
  3. 动态连接,每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,栈帧持有这个引用是为了支持方法调用过程中的动态连接(Dynamic Linking),即,调用一个方法是通过该引用找到运行时常量池中的方法信息的。
  4. 方法返回地址,方法执行结束,不管是正常退出还是异常退出,都需要返回到该方法被调用的位置。

操作栈的压栈与出栈-《码出高效》



本地方法栈

本地方法栈与虚拟机栈类似,不同的是,虚拟机栈是用来执行java方法(class字节码)的,而本地方法栈是用来执行本地方法(native)的,本地方法栈中没有栈帧。例如linux的 .so 或windows的 .dll 都是本地方法,用c++实现的。



java堆

JVM中只有一个堆,且被所有线程共享 ,Java堆是JVM内存中最大的一块区域,用来存放几乎所有对象的实例,堆是不连续的空间,速度慢但更灵活。



方法区

在jdk1.6及之前,用永久代来实现方法区,运行时常量池就在里面,而字符串常量池又在运行时常量池里面。


jdk1.7,字符串常量池从永久代移至堆区,运行时常量依然在永久代


jdk1.8及之后,永久代被元空间取代了。运行时常量池跟着元空间从虚拟机内存迁到了PC本地内存(用以防止方法区频繁的OOM)


运行时常量池:在方法区里面又划分了一块区域为运行时常量池,存放的是常量值的符号引用。类加载时,把某个类的字节码文件加载到内存,同时将class常量池中的内容存放到运行时常量池中;在解析时,JVM把符号引用替换为直接引用,替换的过程就是运行时常量池拿符号引用查询全局字符串池中的直接引用。





我们已经知道:Java中的数据类型有基本数据类型和引用数据类型,那么这些数据的存储都使用哪一种策略呢?

这里要分以下的情况进行探究:

  • 对于局部变量来说,不论是基本数据类型还是引用类型,都在栈中,注意后者只存引用地址

  • 对于成员变量来说,不论是基本数据类型还是引用类型,他们都会存储在堆内存或者方法区中;成员变量可细分为静态成员变量和普通成员变量,静态成员变量类属于类,存储在方法区中;普通成员变量属于类对象,必须声明对象之后,通过对象才能访问,存储在堆中。




面试

百度: 三面:说一下JVM内存模型吧,有哪些区?分别干什么的?

蚂蚁金服: Java8的内存分代改进 JVM内存分哪几个区,每个区的作用是什么? 一面: JVM内存分布/内存结构?栈和堆的区别?堆的结构?为什么两个survivor区? 二面: Eden和Survior的比例分配

小米: jvm内存分区,为什么要有新生代和老年代

字节跳动: 二面: Java的内存分区 二面:讲讲jvm运行时数据库区 什么时候对象会进入老年代?

京东: JVM的内存结构,Eden和Survivor比例 。 JVM内存为什么要分成新生代,老年代,持久代。新生代中为什么要分为Eden和Survivor。

天猫: 一面: Jvm内存模型以及分区,需要详细到每个区放什么。 一面: JVM的内存模型,Java8做了什么修改

拼多多: JVM内存分哪几个区,每个区的作用是什么?

美团: java内存分配 jvm的永久代中会发生垃圾回收吗? 一面: jvm内存分区,为什么要有新生代和老年代?




tangxman.github.io/2015/07/23/… segmentfault.com/a/119000001… juejin.cn/post/685457… segmentfault.com/a/119000001…