首页 > 编程语言 > 详细

浅谈Java中的JVM

时间:2021-08-18 10:17:03      阅读:17      评论:0      收藏:0      [点我收藏+]

浅谈Java中的JVM

Java之所以能够如此流行并且经久不衰,其一次编写,到处运行的特性起到很重要的作用,引出今天的第一个问题。

一、Java为什么能够跨平台运行?

因为Java程序编译之后会生成.class文件,这种文件是不能够被硬件系统直接运行的代码,而是一种中间码——字节码。如果硬件系统想要运行这种代码,就需要JVM的帮助。
JVM(Java Virtual Machine),中文一般叫做Java虚拟机,在不同的硬件平台上安装有不同版本的Java虚拟机,在Java程序编译后,由JVM将字节码翻译成对应平台能够执行的代码。因此对于Java编程者来说,根本不需要考虑硬件平台是什么,可以更加专注在程序本身的逻辑。

Java的跨平台就是通过在不同的平台安装相应的JVM来实现的

技术分享图片
Java的工作过程

二、如何安装JVM

JVM是不能够单独安装的,他是嵌入在JDK或JRE中的。

名词解释
JDK:Java Development Kit(Java开发工具包) JDK作为开发工具,一般都是包含JRE的。
JRE:Java Runtime Environment(Java运行时的环境) JRE本质上是通过JVM虚拟机来运行
JVM:Java Vitual Machine(Java虚拟机)Java的跨平台就是通过在不同的平台安装相应的JVM来实现的

1. JDK JRE JVM的关系:

技术分享图片
JDK,JRE,JVM的关系

Java虚拟机有自己完善的硬件架构,如处理器、堆栈等,还具有相应的指令系统。

三、JVM的内存结构和内存分配

1. JVM 内存模型

技术分享图片
JDK1.8之前

技术分享图片
JDK1.8

1.方法区是静态分配的,编译器将变量绑定在某个存储位置上,而且这些绑定是不会在运行时改变。常量池,源代码中的命名常量String常量static变量保存在方法区。

2.Java stack 是一个逻辑概念,特点是后进先出。一个栈的空间可能是连续的,也可能是不连续的。最典型的stack应用是方法的呃调用,Java虚拟机每调用一次方法就创建一个方法帧(frame),退出该方法则对应的方法帧被弹出(pop)。栈中存储的数据也是运行时确定的。所谓的虚拟机栈就是常说的栈。
本地方法栈和虚拟机栈所发挥的作用非常相似,区别是:虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native方法服务。在HotSpot虚拟机中的Java虚拟机栈合二为一

3.Java堆分配(heep allocation)意味着以随意的顺序,在运行时进行存储空间分配和收回的内存管理模型。堆中存储的数据常常是大小、数量和生命周期在编译时无法确定的。Java对象的内存总是在heap中分配。我们每天都在写代码,每天都在使用JVM的内存。

4.程序计数器:字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理。在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程切换回来的时候能够知道该线程上次运行到哪个位置。

5.JDK1.8的时候,方法区(HotSpot的永久代)被彻底移除了,(JDK1.7就已经开始了),取而代之的是元空间,元空间使用的是直接内存

2. Java的内存分配

1.基础数据类型直接在栈空间分配
2.方法的形式参数,直接在栈空间分配,当方法调用完成后从栈空间释放
3.引用数据类型,需要用new来创建,既在栈空间分配一个地址空间,又在堆空间分配对象的类变量
4.方法的引用参数,在栈空间分配一个地址空间,并指向堆空间的对象区,当方法调用完后从栈空间回收
5.局部变量new出来时,在栈空间堆空间中分配空间,当局部变量生命周期结束之后,栈空间会立刻被回收,堆空间区域等待GC回收
6.方法调用时传入的实际参数,先在栈空间分配,在方法调用完成后从栈空间释放
7.字符串常量在DATA区域分配this在对空间分配
8.数组既在栈空间分配数组名称,又在堆空间分配数组实际的大小

3. JVM垃圾回收机制和常见算法

理论上来讲,Sun公司只定义了垃圾回收机制规则而不局限于其实现算法,因此不同厂商生产的虚拟机采用的算法也不尽相同。
GC(Garbage Collector)在回收对象前首先必须发现那些无用的对象,如何去发现定位这些无用的对象?常用的搜索算法如下:

3-1. 引用计数器算法(废弃)

引用计数器算法是给每个对象设置一个计数器,当有地方引用这个对象的时候,计数器+1,当引用失效的时候,计数器-1,当计数器为0的时候,JVM就认为对象不再被使用,是垃圾了。引用计数器实现简单,效率高但是不能解决循环引用问题(A对象 引用 B对象,B对象 又引用 A对象,但是A,B对象已不被任何其他对象引用),同时每次计数器的增加和减少都带来了很多额外的开销,所以在JDK1.1之后,这个算法已经不在使用了

3-2. 根搜索算法(使用)

根搜索算法是通过一些GC Roots对象作为起点,从这些节点开始往下搜索,搜索通过的路径成为引用链Reference Chain,当一个对象没有被GC Roots的引用链连接的时候,说明这个对象是不可用的

GC Roots 对象包括

a).虚拟机栈(栈帧中的本地变量表)中的引用的对象
b).方法区域中的类静态属性引用的对象
c).方法区域中常量引用的对象
d).本地方法栈中JNI(Native方法)的引用的对象

通过上面的算法搜索到无用对象之后,就是回收过程,回收算法如下:

  1. 标记-清除算法(Mark-Sweep)(DVM使用的算法)

标记-清除算法包括两个阶段:标记清除在标记阶段,确定所有要回收的对象,并做标记清除阶段紧随标记阶段,将标记阶段确定不可用的对象清除。标记-清除算法是基础的收集算法,标记和清除阶段的效率不高而且清除后会产生大量的不连续空间,这样当程序需要分配大内存对象时,可能无法找到足够的连续空间

  1. 复制算法(Copying)

复制算法是把内存分成大小相等的两块,每次使用其中一块,当垃圾回收的时候,把存活的对象复制另一块上,然后把这块内存整个清理掉。复制算法实现简单,运行效率高,但是由于每次只能使用其中的一半,造成内存的利用率不高。现在的JVM用复制方法收集新生代,由于新生代中大部分对象(98%)都是朝生夕死的,所以两块内存的比例不是1:1(大概8:1)

  1. 标记-整理算法(Mark-Compact)

标记-整理算法和标记-清除算法一样,但是标记-整理算法不是把存活对象复制到到另一块内存,而是把存货对象往内存的一端移动,然后直接回收边界以外的内存。标记-整理算法提供了内存的利用率,并且它适合在收集对象存活时间较长的老年代

  1. 分代收集(Generational Collection)

分代收集是根据对象的存活时间把内存分为新生代和老生代,根据各个对象的存活特点,每个带采用不同的垃圾回收算法。新生代采用复制算法,老年代采用标记-整理算法。垃圾算法的实现涉及大量的程序细节,而且不同的虚拟机平台实现的方法也各不相同。

四、JVM的组件

JVM是Java的虚拟机,其大致可以包括

类加载器:用于加载类
垃圾回收器:回收无用的对象
方法区:也称为永久代非堆,它用于存储虚拟机加载的类信息、常量、静态变量、是各个线程共享的内存区域
Java堆:java虚拟机所管理的内存中最大的一个块内存区域,也是被各个线程共享的内存区域,在JVM启动时创建。该内存区域存放了对象实例及数组(所有new出来的对象)。由于现在收集器都是采用分代收集算法,堆被划分为新生代和老生代。新生代主要存储新创建的对象和尚未进入老年代的对象。老年代存储经过多次新生代GC(Minor GC)仍然存活的对象。
Java栈:描述的是Java方法执行的内存模型:每个方法被执行的时候都会创建一个栈帧,用于存储局部变量表(包括参数)、操作站、方法出口等信息。每个方法被调用到执行完的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。生命周期与线程相同,是线程私有的。
本地方法栈:与虚拟机栈基本类似,区别在于虚拟机栈为虚拟机执行的Java方法服务,而本地方法栈则是为Native方法服务
执行引擎
本地方法接口
指令寄存器

技术分享图片
JVM结构图

浅谈Java中的JVM

原文:https://www.cnblogs.com/Breety/p/15154542.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!