Java堆与栈的基本理解

Java堆与栈的基本理解

最新的一次面试,我们聊到了JVM,今天在这儿想要系统的回顾一下,记录在此,时常看看,增加自己的印象。

Java虚拟机运行时数据区

首先,线程隔离的数据区域内包含:程序计数器、虚拟机栈、本地方法栈。
其次,所有线程共享的数据区域包含:堆、方法区、运行时常量。

程序计数器

程序计数器是一个记录着当前线程所执行的字节码的行号指示器。
字节码解释器工作是就是通过改变这个计数器的值来选取下一条需要执行指令的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖计数器完成。此内存区域是唯一一个没有规定任何OutOfMemoryError情况的区域。线程私有。
如果线程正在执行一个 Java 方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址,如果线程执行的是一个Native方法,计数器值则为空。

虚拟机栈

Java虚拟机栈也是线程私有的,它的生命周期与线程相同(随线程而生,随线程而灭),Java虚拟机栈描述的是Java方法执行的内存模型:每个方法执行的同时会创建一个栈帧,用于存储局部变量表操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行结束,就对应着一个栈帧从虚拟机栈中入栈到出栈的过程。
(局部变量表(Local Variable Table)是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量, 并且在Java编译为Class文件时,就已经确定了该方法所需要分配的局部变量表的最大容量。局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double对象引用(reference类型) 和 returnAddress类型,也可以说基本数据和对象引用存储在栈的局部变量表中
如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常,如果虚拟机栈可以动态扩展,如果扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常(当前大部分JVM都可以动态扩展,只不过JVM规范也允许固定长度的虚拟机栈)。

本地方法栈

和Java虚拟机栈十分相似,差别不过是Java虚拟机栈是为了Java虚拟机执行字节码所服务,而本地方法栈则是为了执行native方法所服务的,所以本地方法也是一个私有的内存区域,也是后进先出栈,作用是支撑native方法的调用,执行和退出与java虚拟机栈一样也会出现StackOverflowError 和 OutOfMemoryError 异常。

堆是 JVM 管理的最大的一块内存空间,主要用于存放Java类的实例对象,其被划分为三个不同的区域:新生代 ( Young )和老年代 ( Old )和永久代(Pem),从Java8中元空间替代了永久代。
Java堆可以处于物理上不连续的内存空间中,并且可以动态扩展其内存,扩展失败将会抛出OutOfMemoryError异常。
堆内存中存储的全部是对象,所有的实体都有内存地址值。当这些实体不再被指向时,JVM启动垃圾回收机制。

方法区

用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。与堆一样是线程共享的内存区域,也不需要连续的内存,可动态扩展内存,扩展失败一样会抛出OutOfMemoryError异常。

常量池

这里说到的是运行时常量池。属于方法区一部分,用于存放编译期生成的各种字面量和符号引用。编译器和运行期都可以将常量放入池中。内存有限,无法申请时抛出 OutOfMemoryError。
网上常用的案例:

String s1 = "Hello";	 
String s2 = new String("Hello");
String s3 = s2.intern();

其中s1和s3为什么相等呢?原因在于intern方法,这个方法首先在常量池中查找是否存在一份equal相等的字符串如果有的话就返回该字符串的引用,没有的话就将它加入到字符串常量池中,所以存在于class中的常量池并非固定不变的,可以用intern方法加入新的。

总结

我们面试中常会问到堆栈的问题。
函数中定义的基本类型变量,对象的引用变量都在函数的栈内存中分配。栈内存特点是数据一执行完毕,变量会立即释放,节约内存空间。栈内存中的数据,没有默认初始化值,需要手动设置。(String s = “abc”,其中s就是在栈中)
堆内存用来存放new创建的对象和数组。堆内存中所有的实体都有内存地址值。堆内存中的实体是用来封装数据的,这些数据都有默认初始化值,当实体不再被指向时,JVM启动垃圾回收机制,自动清除。(String s= new String ("abc),其中这个new的对象则是在堆中)
常见的面试问题->String s = new String(“abc”)产生几个对象?->该问题涉及到常量池,如果之前常量池没有“abc”这个对象,则会先在常量池中创建一个该字符串对象,然后在堆中创建一个拷贝对象,这样的话则会产生2个对象;如果常量池中有该对象,则只创建一个对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值