JVM初识

1.JVM是什么标题?

JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。
引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。

2.JVM的分类

Sun公司的HotSpot 是目前使用范围最广的Java虚拟机。

BEA公司的JRockit(原来的 Bea JRockit)电脑软件,系列产品是一个全面的Java运行时解决方案组合。

IBM公司的J9 VM 是一个高性能的企业级 Java 虚拟机。

2.JVM的位置

位于操作系统之上。
一个.java文件的运行过程:
Java源文件>编译器>字节码文件(.class)>JVM解释器解释>机器码(01100)

3.JVM的体系结构

在这里插入图片描述
简单的内存分配图
在这里插入图片描述
在这里插入图片描述

3.1类加载器

1.启动类加载器bootstrap classloader:加载jre/lib/rt.jar
2.扩展类加载器 extension classloader: 加载jre/lib/ext/*.jar
3.应用程序加载器 application classloader :加载classpath上指定的类库
4.用户自定义加载器 User ClassLoader ;
双亲委派机制
原理:当一个类加载器收到一个类加载器的请求时,该类加载器首先会把请求委派给父类加载器。每个类加载器都是如此,只有在父类加载器在自己指定的搜索范围内找不到指定的类时,子类加载器才会自己去尝试加载。
例子:当一个Hello.class这样的文件要被加载时。不考虑我们自定义类加载器,首先会在AppClassLoader中检查是否加载过,如果有那就无需再加载了。如果没有,那么会拿到父加载器,然后调用父加载器的loadClass方法。父类中同理会先检查自己是否已经加载过,如果没有再往上。注意这个过程,直到到达Bootstrap classLoader之前,都是没有哪个加载器自己选择加载的。如果父加载器无法加载,会下沉到子加载器去加载,一直到最底层,如果没有任何加载器能加载,就会抛出ClassNotFoundException。

car.class->classLoader->加载并初始化(car class)->new (car 的实例)
在这里插入图片描述

3.2虚拟机栈(VM Stack)

描述java方法执行的内存模型,用于存放该线程执行方法的信息(如局部变量,操作数,方法出口等),特点是:速度快,连续空间,先进后出,线程私有,生命周期和线程同步,不存在垃圾回收。八大基本数据类型、实例的方法、对象的引用都是在函数的栈内存中分配的。
常见的报错信息在这里插入图片描述

3.3本地方法栈(Native Method Stack)

本地方法栈服务的对象是JVM执行native 的方法。
Native:凡是带了native关键字,JAVA程序操作不了底层,调用底层语言的库。native主要应用在方法上,一个native方法就是一个Java调用非Java代码的接口。该方法的实现由非Java实现,如C,C++.
Java语言本身不能实现对操作系统底层进行访问和操作,但是可以通过JNI接口调用其他语言来实现对底层语言的访问。
过程:首先进入到本地方法栈中登记,然后调用本地方法接口(JNI),JNI再调用相应的类库。

3.4PC寄存器

每个线程都有一个程序计数器,是线程私有的,就是一个指针,指向方法区中的方法字节码(用来存储指向下一条指令的地址,也即将要执行的指令代码),由执行引擎读取下一条指令,是一个非常小的内存空间,几乎可以忽略不记。

3.5方法区:Java虚拟机规范中的定义。

方法区是线程共享的,通常用来保存装载的的元结构信息。
比如:运行时常量池+静态变量+常量+字段+方法字节码+在类/实例/接口初始化用到的特殊方法等。
存放的是程序中永远不变或唯一的内容。

3.6堆heap:用于存储被创建好的对象。

1.内存划分为堆内存和非堆内存,堆内存分为年轻代(Young Generation)、老年代(Old Generation),非堆内存就一个永久代(Permanent Generation)。
2.年轻代又分为EdenSurvivor区。Survivor区由FromSpace和ToSpace组成。Eden区占大容量,Survivor两个区占小容量,默认比例是8:1:1。
3.堆内存用途:存放的是对象,垃圾收集器就是收集这些对象,然后根据GC算法回收。
4.非堆内存用途:永久代,也称为方法区,存储程序运行时长期存活的对象,比如类的元数据、方法、常量、属性等。
在这里插入图片描述
在JDK1.8版本废弃了永久代,替代的是元空间(MetaSpace),元空间与永久代上类似,都是方法区的实现,他们最大区别是:元空间并不在JVM中,而是使用本地内存
在堆中垃圾回收过程:
首先新生成的对象都是放在Eden区,当Eden区满了不能创建对象,则触发Minior GC,
将无用的对象清除,有用的对象复制到Survivor中任意一个区(如s1),同时清空Eden区。
当Eden区再次满了,将s1和Eden区有用的对象复制到s2区。(如此循环下去,保证Survivor区一个有用一个为空,Survivor区中对象有年龄,默认超过15次GC的,复制到Old区)
Old区的对象达到一定比例启动Major GC。
当Old区也满了将会触发一次完整地垃圾回收(FullGC).

3.7永久代和元空间内存使用上的差异:

存储内容不同,元空间只存储类和类加载器的元数据信息,静态变量和常量池等并入堆中。相当于永久代的数据被分到了堆和元空间中。

Java虚拟机规范中只定义了方法区用于存储已被虚拟机加载的类信息、常量、静态变量和即时编译后的代码等数据

1)jdk1.7开始符号引用存储在native heap中,字符串常量和静态类型变量存储在普通的堆区中,但分离的并不彻底,此时永久代中还保存另一些与类的元数据无关的杂项

2)jdk8后HotSpot 原永久代中存储的类的元数据将存储在metaspace中,而类的静态变量和字符串常量将放在Java堆中,metaspace是方法区的一种实现,只不过它使用的不是虚拟机内的内存,而是本地内存。在元空间中保存的数据比永久代中纯粹很多,就只是类的元数据,这些信息只对编译期或JVM的运行时有用。

3)永久代有一个JVM本身设置固定大小上线,无法进行调整,而元空间使用的是直接内存,受本机可用内存的限制,并且永远不会得到java.lang.OutOfMemoryError。
    
4) 符号引用没有存在元空间中,而是存在native heap中,这是两个方式和位置,不过都可以算作是本地内存,在虚拟机之外进行划分,没有设置限制参数时只受物理内存大小限制,即只有占满了操作系统可用内存后才OOM。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值