首页 > 系统相关 >【后端面经-Java】JVM内存分区详解

【后端面经-Java】JVM内存分区详解

时间:2023-07-17 09:12:14浏览次数:43  
标签:Java 常量 端面 内存 JVM 字符串 方法

@

目录

1. JVM内存分区简介

JVM内存分区如图所示:

主要有如下几个区域:

  • 栈(Stack)
  • 堆(Heap)
  • 方法区(Method Area)
  • 程序计数器(PC)
  • 本地方法栈(Native Method Stack)

其中,程序计数器用于存储线程当前执行的指令地址(记录进度),程序计数器是线程私有的;
本地方法栈并不是每个JVM都必须实现,而是针对支持native本地方法调用的JVM。

  • 本地方法:使用非Java语言定义的方法;
  • 本地方法栈同一般的JVM栈一样,可分配固定或者动态内存。

剩余的三个区域:栈、堆、方法区,在下文中会详细介绍。

2. JVM栈

Java栈的基本存储单元为栈帧,每个线程对应一个栈帧,不同栈帧之间不会共享数据。
栈帧主要包括:

  • 局部变量:在方法内部定义的变量
  • 操作数栈:函数形参
  • 指向运行时常量池的引用
  • 方法返回地址
  • 附加信息

JVM栈的内存大小可以固定设置也可以动态分配,当出现栈溢出的时候,固定内存的栈会抛出StackOverFlowError,而动态分配的栈则会抛出OutOfMemoryError

3. JVM堆

JVM堆中存放的是对象实例(说人话就是用new创建的对象,因为数组也是new int[]这种形式创建的,所以JVM将数组看作一种特殊的对象)。
JVM堆是线程共享的,可动态分配内存。
需要注意的是,当一个方法结束之后,JVM栈中的相关数据会出栈,释放内存,但是对于JVM堆,虽然创建对象的方法已经消失,但是对象本身并不会在堆中被销毁,而是会等待垃圾回收机制进行内存回收。

4. JVM方法区

JVM方法区主要用于存放已被加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
方法区是线程共享的。
方法区中有个区域叫做常量池,包括静态常量池运行时常量池
静态常量池存放的是编译时就能够确定的常量数据,包括一些常数、类信息、方法信息等等;
运行时常量池存放的是运行时才能够确定的常量数据。

需要注意的是,运行时常量池在JDK1.7之后不再放在方法区中,而是放在堆中。

因此,对于常见的字符串常量池,如果一个字符串在编译时可以确定值,那么就放在方法区静态常量池中,如果在运行时遇到字符串先查找常量池,常量池中没有该字符串,则该字符串被创建,创建的对象会放在运行时常量池中,放在方法区还是堆中就需要根据版本来确定。

5. JVM内存分配实例

public class Demo {
	String username;
	public void method() {
        int i=1;
		System.out.println("执行类方法");
	}
	public static void main(String[] args) {
		int i=1;
		String str="hello java";
		Demo demo=new Demo();
		demo.username="123";
		demo.method();
		
	}
 
}
//出处:https://blog.csdn.net/m0_57816620/article/details/127332057?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2~default~CTRLIST~Rate-1-127332057-blog-125451232.235%5Ev38%5Epc_relevant_anti_t3&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~CTRLIST~Rate-1-127332057-blog-125451232.235%5Ev38%5Epc_relevant_anti_t3&utm_relevant_index=2

对于上面的Java代码,各位可以思考一下内存分配的具体情况。

  1. Demo类编译的时候产生.class文件,放在方法区的静态常量池中,存储类信息;
  2. 从Demo类的main方法进入,方法main的内存地址入栈,
  3. int i=1;创建一个局部变量i,值为1,入栈;
  4. String str="hello java";创建一个字符串变量str,入栈;对于hello java这个字符串常量,JVM查找静态常量池运行时常量池中是否存在该字符串,如果存在,字符串变量str直接指向该字符串常量,如果不存在,则创建一个字符串常量hello java,并将该字符串常量放入运行时常量池中,然后字符串变量str指向该字符串常量;
  5. Demo demo=new Demo()创建一个对象变量demo,入栈;对于对象实例本身,则会创建之后存于堆中,然后demo变量指向该对象实例;
  6. demo.username="123"修改类中的属性值,在堆中设置username变量,值为123;
  7. demo.method()调用类方法,方法定义存于JVM方法区中,取出该方法信息,然后进入method方法,开启新一个线程,JVM栈帧加1,存放method方法的内存地址;
  8. 执行method方法,int i直接将局部变量入栈;
  9. System.out.println("执行类方法");则是调用System.out.println方法(库方法);
  10. method方法执行完毕,栈帧出栈;
  11. main方法执行完毕,栈帧出栈。
  12. 栈中无栈帧,结束进程;而此时堆中依然保留Demo对象实例,等待垃圾回收机制回收。

面试模拟

Q:JVM堆、栈、方法区的作用
A:JVM栈存放方法调用时的局部变量、形参、返回地址等信息,每个方法调用的时候都会产生一个栈帧,出入栈操作实现方法的嵌套调用;
堆中存放的是对象实例或者数组,是线程共享的,可动态分配内存;
方法区存放的是一些静态变量和常量数据,包括类编译的方法和属性信息,静态常量池和运行时常量池在JDK1.6均属于此类。

参考资料

  1. Java JVM 中 堆,栈,方法区 详解
  2. Java堆、栈、方法区、常量池
  3. java内存分配(堆,栈,方法区,常量池)图解
  4. Java内存模型(JMM)总结

标签:Java,常量,端面,内存,JVM,字符串,方法
From: https://www.cnblogs.com/CrazyPixel/p/17559094.html

相关文章

  • Java8新特性之Optional类的妙用
    该新特性也是翻java八股翻到的,感觉有点小用,所以记录一下通常我们在调用方法获取参数时,常常会出现要避免空指针,从而进行一系列判断非空的代码,这部分十分冗长且啰嗦还重复,故可以使用一下今天的主角:Java.util.Optional类创建方式共有三种方式供您选择直接创建空的Optional对......
  • JVM专栏-内存分配与回收策略
    对象的内存分配,就是在堆上分配(也可能经过JIT编译后被拆散为标量类型并间接在栈上分配),对象主要分配在新生代的Eden区上,少数情况下可能直接分配在老年代,分配规则不固定,取决于当前使用的垃圾收集器组合以及相关的参数配置。以下列举几条最普遍的内存分配规则,供大家学习。对象优......
  • JVM专栏-类文件结构
    JVM的“无关性”谈论JVM的无关性,主要有以下两个:平台无关性:任何操作系统都能运行Java代码语言无关性:JVM能运行除Java以外的其他代码Java源代码首先需要使用Javac编译器编译成.class文件,然后由JVM执行.class文件,从而程序开始运行。JVM只认识.class文件,......
  • JVM专栏-类加载的时机
    类加载的时机类的生命周期类从被加载到虚拟机内存开始,到卸载出内存为止,它的整个生命周期包括以下7个阶段:加载验证准备解析初始化使用卸载验证、准备、解析3个阶段统称为连接。加载、验证、准备、初始化和卸载这5个阶段的顺序是确定的,类的加载过程必须按照这种......
  • 使用Java线程同步工具类CountDownLatch
    java.util.concurrent.CountDownLatch是Java并发并发编程中的线程同步工具类,基于AQS(java.util.concurrent.locks.AbstractQueuedSynchronizer)实现。CountDownLatch工具类主要应用在如下场景:等待一组线程执行完毕后继续执行后续操作。应用举例:模拟使用多个线程同时调用多个RPC方......
  • 使用Java线程同步工具类CyclicBarrier
    如何使用java.util.concurrent.CyclicBarrier是Java并发并发编程中的线程同步工具类,基于java.util.concurrent.locks.ReentrantLock实现。CyclicBarrier工具类主要应用在如下场景:让一组线程同时到达栅栏位置才能开始执行。应用示例:publicstaticvoidmain(String[]args){......
  • javascript 快排
    functionquickSort(arr){//如果数组只有一个数,就直接返回;if(arr.length<1){returnarr;}//找到中间的那个数的索引值;如果是浮点......
  • 【技术积累】JavaScript中的基础语法【二】
    JavaScript编写方式JavaScript是一种脚本语言,用于为网页添加交互性和动态功能。它可以直接嵌入到HTML中,并通过浏览器解释执行。下面是一些常见的JavaScript编写方式和相应的代码示例:内联方式在HTML文件中直接嵌入JavaScript代码,使用`<script>`标签将代码包裹起来。这种方式适用......
  • Java数组
    Java数组数组的定义数组是相同类型数据的有序集合。数组描述的相同类型的若干个数据,按照一定的先后次序排列组合而成。其中,每一个数据称作一个数组元素,每个数组元素可以通过一个下标来访问它们。数组声明创建首先必须声明数组变量,才能在程序中使用数组。下面是声明数组......
  • Java开发大型互联网-架构师必须掌握的分布式技术
    Java开发大型互联网-架构师必须掌握的分布式技术摘要:在当今互联网行业,随着用户量和业务的不断增长,大型互联网系统的设计和开发已经成为了一项头等重要的任务。作为架构师,要能够应对这样的挑战,就必须掌握一些关键的分布式技术。本文将介绍Java开发大型互联网系统时,架构师必须要掌......