java虚拟内存
jvm逻辑内存
1.程序计数器:
每个线程都有自己的一个计数器(因为线程切换时,需要计数器记录执行的位置,这样才能在线程恢复时回到正确的执行位置),记录线程执行的字节码的行号指示器。分支,循环,跳转,异常处理以及线程恢复等都需要这个计数器
。此区域是线程私有区域
2.虚拟机栈:也是线程私有的空间。生命周期跟线程相同。它描述的是方法的内存模型。当线程调用方法时,会创建
栈帧
。栈帧,是用于存放
局部变量表
(老马说的栈内存,是存放编译期间可知的基本类型和对象引用),
方法返回出口
,
操作栈
和
动态链接
。在方法被执行时会创建栈帧,并将起放入虚拟机栈,直到方法执行结束后出栈。
补充:
除64位的long和double会占用两个局部空间,其他的基础类型只占用一个,
在Java 虚拟机规范中,对这个区域规定了两种异常状况:如果
线程请求的栈深度
大于虚拟机所允许的深度,将抛出
StackOverflowError
异常;如果虚拟机栈可以动态扩展(当前大部分的Java 虚拟机都可动态扩展,只不过Java 虚拟机规范中也允许固定长度的虚拟机栈),当扩展时无法申请到足够的内存时会抛出OutOfMemoryError 异常。
3.本地方法栈:
只为native方法服务,与虚拟机栈一样,本地方法栈区域也会抛出StackOverflowError 和OutOfMemoryError异常
4.java堆:
各个线程共享的区域,GC垃圾收集管理的的主要区域,如果在堆中没有内存分配实例空间,并且堆的内存无发扩张时,会抛出OutOfMemoryError异常
新生代
老年代(标记清除,标记整理算法)
还细分为:Eden空间,from Survivor空间,to Survivor空间(复制算法)
分配缓冲区TLAB
5.方法区(非堆,也有人称为永久代):
也是各个线程共享的区域,
内存回收目标:针对常量池的回收及类型的卸载,相对而言垃圾收集行为比较少
,当方法区内存无法满足分配需求是,也会抛出OutOfMemoryError异常
存放:类信息、常量、静态变量和即时编译器编译的代码
5.1运行时常量池(是方法区的一部分):
保存Class文件中描述的符号常量,也会保存翻译后的直接引用。String.intern()方法,可以在运行时将常量放到运行时常量池中
java逻辑内存的关联关系
举例说明:假设在方法里面有一条语句 Object obj = new Object();
java虚拟机栈:在局部变量表中会存放
引用类型
Object obj
引用定位对象的方式有两种:使用句柄或直接引用
方式一:使用句柄(句柄池),reference存储的是句柄池的地址信息
方式二:直接引用(对象地址),
reference存储的是对象地址
★★两种方式对比
使用句柄:在对象被移动时(垃圾回收),只会影响句柄池中实例对象的指针
直接引用:直接指向对象实例,少一次寻址的过程
java堆:会为new Object()新创建的对象分配内存空间,同时还必须要
保存查找此对象数据类型的
地址信息
(对象类型、父类、接口、实现的方法等)
java方法区:存储对象类型、父类、接口、实现方法的的
数据