JVM内存管理

JVM内存布局

java数据结构

- 静态成员变量
- 类的常量
- 动态成员变量
- 局部变量(区域变量)
- 短小紧凑的对象声明
- 庞大复杂的内存申请

java内存区域划分

java 7 及其以前内存划分:

方法区:线程共享,JVM启动时创建,关闭时销毁。存放类的信息,静态变量,类常量池,字符串常量池
堆:线程共享,JVM启动时创建,关闭时销毁。存放类的实例
Java虚拟机栈:线程私有,跟程序计数器配(记录方法执行字节码行号-字节码行号记录器;执行引擎线程切换时记录切换线程执行的字节码行号)对出现。线程执行方法时,创建对应的栈,执行完毕后销毁。有局部变量表,操作数栈,动态链接,返回地址
本地方法栈:线程私有,执行本地方法。会有报错OutOfMemoryError:当前线程申请栈时,发现栈已经满了,内存也用光。
程序计数器:线程私有,记录java方法时字节码指令的地址;执行引擎进行线程切换时记录线程java方法执行的位置;不存在内存溢出情况。不记录本地方法栈相关信息
  • java 7 内存模型图
     java 7 内存模型

Java 8内存模型

方法区:线程共享,JVM启动时创建,关闭时销毁。存放类的信息,静态变量,类常量池,运行时常量池
堆:线程共享,JVM启动时创建,关闭时销毁。存放类的实例,字符串常量池(执行String.intern()方法的位置)
Java虚拟机栈:线程私有,跟程序计数器配(记录方法执行字节码行号-字节码行号记录器;执行引擎线程切换时记录切换线程执行的字节码行号)对出现。线程执行方法时,创建对应的栈,执行完毕后销毁。有局部变量表,操作数栈,动态链接,返回地址
本地方法栈:线程私有,执行本地方法。会有报错OutOfMemoryError:当前线程申请栈时,发现栈已经满了,内存也用光。
程序计数器:线程私有,记录java方法时字节码指令的地址;执行引擎进行线程切换时记录线程java方法执行的位置;不存在内存溢出情况。不记录本地方法栈相关信息

  • java 8 内存模型
    java 8 内存模型

  • 从JVM内存区域所示,得出:

JVM堆中数据时共享的,是内存最大的一块区域
可以执行字节码的模块叫执行引擎
执行引擎在线程切换时恢复依靠的程序计数器
JVM内存划分与多线程息息相关。运行时用的栈,以及本地方法栈,维度都是线程
本地内存包含元数据区和一些直接内存。

java虚拟机栈

  • 上文提到,java虚拟机栈基于线程,main方法也是以线程方式运行的。线程生命周期中,参与计算的数据会频繁的入栈和出栈,栈的声明周期和线程一样
  • 会在线程申请栈时报StackOverflow,是因为在申请栈时,已经超出栈的最大深度,但此时内存空间还有很多;会在内存用完的时候,线程申请栈时报OutOfMemoryError
  • 组成部分
局部变量表:存放方法的局部变量
操作数:
动态链接
返回地址
  • java虚拟机栈
    java虚拟机栈

本地方法栈

  • 与java虚拟机栈非常相似的区域,服务对象是native方法。甚至可以认为虚拟机栈和本地方法栈是同一个区域,者并不影响对JVM了解。
  • 特殊数据类型-returnAddress
1.returnAddress:存在于字节码层面。对于JVM来说,程序就是存储在方法区的字节码指令,而returnAddress类型的值就是指向特定内存地址的指针。
2.这里有两层栈:第一层对于方法,第二层是方法执行,对应着操作数。
3.可以看到,所有字节码指令,其实都会抽象成对栈的入栈出栈操作。
执行引擎只需要傻瓜式的按顺序执行,就可以保证他的正确性。

  • java-本地方法栈-returnAddress
    java-本地方法栈-returnAddress

程序计数器

  • 记录java方法执行字节码的地址,配合虚拟机栈完成计算操作。存储当前正在运行流程流程,包括正在执行的指令,跳转,分支,循环,异常处理等

  • 执行引擎进行线程切换时,依靠对应线程的程序计数器来找到上次执行字节码的地址,接着执行。线程CPU获取CPU时间片是不可预知的,需要程序计数器,对线程正在运行的地位进行缓冲记录,以便在获取CPU时间片是能够快速恢复。

  • 较小内存区域,不会引起内存问题,其作用可以看成记录当前线程执行字节码的行号指示器。存的是当前线程执行的进度。
    Java方法程序计数器

  • javap 输出的字节码,每个opcode都有一个序号,即红框的偏移地址,可认为是程序计数器内容
     javap 输出的字节码

  • JVM最大内存区域,大部分对象都在此存储,GC进行操作的区域就是堆
  • 在JVM启动时创建,关闭时销毁,不一定会全部使用其空间
  • 随着对象创建增大,堆空间占用增多,需要不定期对不使用对象进行回收,即GC
  • 对象大小不一,长时间运行,会产生细小空间碎片,造成空间浪费,进行对象回收的同时,还要进行堆空间整理
  • 对象分配的位置
一般的:
1.基本数据类型(byte,short,int,long,float,long,boolean)分配在栈上
2.普通对象,JVM会在堆上创建对象,然后在其他对象使用的是它的引用,如将引用保存在虚拟机栈的局部变量表,类似int数组的类型非基本数据类型,也在堆上。

特别的:
1.jvm会判断对象是否存在线程逃逸,如果不存在就直接在栈上分配对象
  • java-方法中对象引用java-方法中对象引用

    • 堆是线程共享的,如果是多个线程访问,会涉及数据同步问题。

元空间

  • 不同于PermGen,其在堆外进行内存分配,非堆内存,使用操作系统内存,不再存在内存溢出。但无限制使用操作系统内存会造成操作系统的死亡。
  • 使用 -XX:MaxMetaspaceSize控制元空间大小
  • 是一个概念,依然存在,物理存储的容器,即Metaspace
  • 包含类的信息,运行时常量池,方法数据,方法代码
  • java 方法区与元空间对比
    在这里插入图片描述
    (8)小结
  • 字符常量存放位置
Java 7 及以前是在PermGen;Java8后在堆上
  • 堆、非堆、本地内存关系
堆是软绵绵,松散有弹性;非堆冷冰生硬,非常紧凑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值