jdk .17
jdk 1.6
jdk1.8
程序计数器:一块比较小的内存,可以看成是当前线程所执行的字节码的行号指示器
java虚拟机栈:每个方法执行的同时都会创建一个栈帧用于存储局部变量表,操作数栈,动态链接,方法出口等信息。每一个方法调用直至执行完成的过程,就对应一个栈帧在虚拟机中入栈和出栈的过程 1.和线程相关,不同线程内,运行同一个方法,也是处于不同内存 2.和方法相关,即使是同一个线程,递归调用某个方法,每次调用都会生成该次方法调用的栈帧 之前我们一直讲的栈区域实际上就是此处的虚拟机,再详细一点,是虚拟机中的局部变量表部分 此区域会产生以下两种异常: 1.如果线程请求的栈深度大于虚拟机所允许的深度(-Xss设置栈容量),将会抛出StackOverFlowErrow(栈溢出)(方法调用太深,比如递归,每次调用都是一次入栈,入栈的数量太多,就会抛出异常)异常。 2.虚拟机在动态扩展时无法申请到足够的内存,会抛出OOM(outOfMemoryError)异常
面试:内存泄露与内存溢出的区别? 内存溢出 (outOfMemoryError):应用系统中存在无法回收的内存过多,最终使得程序运行要用到的内存大于能提供的最大内存 结果:此时程序运行不了,系统会提示内存溢出(进程都会挂掉,情况严重) 内存泄漏(Memory Leak):是指程序中移动已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果 情况:长生命周期的存活的对象,内部持有不适用对象的引用,导致不使用的垃圾对象无法回收 例子:在使用长期存活的数据结构,数组时,都要考虑对象引用导致内存泄露的问题
本地方法栈:与虚拟机栈的作用完全一致,他两的区别无非就是本地方法栈为虚拟机使用的Native方法服务,而虚拟机为JVM执行的java方法服务 test(array,10) test(array,9) index=10该次调用 1.生成index=10的方法栈帧 2.传入参数作为方法内的局部变量定义赋值 3.方法内定义的其他局部变量 以上信息都保存在方法栈帧中 方法进入线程内jvm虚拟机入栈, 方法结束:出栈
java堆:在jvm启动时创建,所有的对象实例以及数组都要在堆上分配 如果在堆中没有足够的内存完成 实例分配并且堆也无法在扩展时,将会抛出OOM
方法区/元数据:用于存储已被虚拟机加载的类信息,常量,静态变量,及时编译器编译后的代码等数据 此区域的内存回收主要是针对常量池的回收以及类型的卸载,当此区域无法完成内存分配需求时,将会抛出OOM异常
public void test(){ String s1=“hello”; String s2=new String(“hello”); } s1,s2为test方法中的局部变量 s2变量的定义 “hello”字符串对象:创建或者获取字符串 new String():传入参数为字符串对象;堆里边String对象,value属性指向字符串对象 =:将堆中String对象赋值给s2,s2引用指向对象
变量对象和内存: String s1=new String("hel)+new String(“lo”); s1.intern();// 获取一个字符串对象或者创建一个引用 String s2=new StingBulider().append().toString(); s2.intern();
直接内存:
class常量池,运行时常量池:
class文件中除了有类的版本,字段,方法,接口等描述信息, 用于存放编译期生成的各种字面值和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。
各种字面值和符号引用:编译时生成的信息,要在运行后,类加载时把变量和对象的引用在内存中联起来。编译时无法关联,所以使用符号引用间接关联。