JVM架构、运行时数据区


 

jvm架构

在这里插入图片描述

  • 类加载器:加载.class文件到内存,创建对应的class对象
  • 执行引擎:对命令进行解析
  • 本地方法库:融合不同开发语言的原生库为java所用
  • 运行时数据区:包含方法区、堆、程序计数器、java虚拟机栈、本地方法栈

 

jvm运行时数据区 | jvm内存模型

运行时数据区也叫作jvm内存模型,JVM Memory Model,JMM

  • 线程共享数据区:方法区、堆,所有线程共享;
  • 线程隔离数据区:程序计数器、java虚拟机栈、本地方法栈,线程独有,生命周期与所在线程的生命周期一致
     

上面的图片只是jvm规范,不同种类的jvm实现可能有差异。

主流的jvm是HotSpot,HotSpot实现方法区的方式如下

  • jdk7及之前:用永久代(PermGen)实现方法区,并把永久代放到堆中,作为堆的一部分,使用堆内存,受堆内存大小限制。
  • jdk8及之后:以后使用元空间(MetaSpace)实现方法区,使用本地内存,不使用堆内存,受本地内存(机器内存)限制。

 

程序计数器

Program Counter。程序计数器占用很小的一块内存空间,每条线程都有1个程序计数器,用来记录当前线程的执行到的位置

线程是一个独立的执行单元,由CPU控制执行,当前线程的时间片用完之后,程序计数器记录执行到的位置,重新获取时间片后,恢复到该位置,从该位置继续往下执行。

 

java虚拟机栈

java虚拟机栈用于方法执行。

jvm执行每个方法时都会创建一个栈帧(Stack Framel),用于存储局部变量表、操作数栈、动态链接、方法出口等信息。方法调用到执行完毕,对应栈帧在java虚拟机栈中入栈到出栈的过程。

局部变量表存储编译期可知的局部变量,如果是局部变量是对象,则存储该对象的引用。

 public void a(){

 }

 public void b{
     a();
 }

b()的执行流程:

  • 先创建b的栈帧,b的栈帧入栈
  • 执行到调用a()时,先创建a的栈帧,a的栈帧入栈
  • a()执行完毕=>a的栈帧出栈,执行b的栈帧
  • b()执行完毕,b的栈帧出栈

java虚拟机栈,栈,先进后出

如果递归调用、且递归没有出口,则执行时会给递归方法创建无数栈帧,java虚拟栈内存耗尽,最终栈溢出,抛出 StackOverflowError 异常。

 

本地方法栈

Native Method Stack。本地方法栈和java虚拟机栈差不多,区别是:

  • java虚拟机栈用于执行java语言编写的方法
  • 本地方法栈用于执行本地方法(native方法),native方法就是用其它语言编写的方法,比如c、c++写的,因为用关键字native修饰,所以叫做native方法

 

方法区

Methoad Area。方法区用于存储已加载的类的信息、常量、静态变量等。

 

方法区之常量池

常量池是方法区的一部分,加载类的class对象后,类、方法的信息,及类中的字面量、符号引用会存储在方法区的常量池中。

字面量指的是8种基本类型、String的常量值,常量池会缓存这些类型的常量值,使得在运行过程中速度更快、更节省内存。
 

String str1="hello";
String str2="hello";

String str3=new String("hello");
String str4=new String("hello");

System.out.println(str1==str2);  //true
System.out.println(str3==str4);  //false
System.out.println(str1==str3);  //false

常量池使用HashSet存储数据,没有重复的数据(常量)。
创建str2时,常量池中已经有了"hello",str2直接指向这个已存在的常量,str1==str2;

str3、str4都是new出来的,new出来的是对象,对象存储在堆中,每次new都是重新分配内存空间。str1是常量池中的常量,str3是堆中的对象,不相等;str3、str4都是堆中的对象,但地址不同,不相等。

 

==与equals()

==,如果是基本数据类型、""的String,根据值(内容)来比较;如果是引用类型(包括new出来的String),根据对象地址来比较;如果一个是前者,一个是后者,自然不等。
 

equals(),根类Object的equals()和==完全等价,因为本来就是使用==来判断

// Object类的equals()源码
public boolean equals(Object obj) {
    return (this == obj);
}

但jdk自带的类基本都重写了equals()、hashCode(),equals()根据内容来比较,我们自定义的类,如果没有继承jdk自带的类、没有重写equals(),那equals()就是继承Object的,和==等价。

 

Heap。堆是jvm中最大的一块内存,是垃圾收集器管理的主要区域,几乎所有的数组、对象都在堆中分配。

 

堆、栈的区别
在这里插入图片描述

 

直接内存 Direct Memory

jvm运行时数据区还有一块可操作的内存区域,直接内存。只是直接内存并非像其它5个区域一样是jvm进程私有,所以一些划分方案没有划分到jvm运行时数据区中。

在 JDK 1.4 中引入了 NIO,可以使用 Native 函数库直接分配堆外内存,然后通过 Java 堆中的 DirectByteBuffer 对象作为这块内存的引用进行操作,避免了在堆内存和堆外内存之间的数据拷贝,提高了性能。使用的不是jvm进程本身的内存,也叫作直接内存。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值