您的位置 首页 > 德语常识

jvm教程,jvm简单理解

本文旨在分享有关Java 和JVM 的知识。这些是学习过程中的笔记和总结。组织记录的过程不仅仅是将它们记录在头脑中。设定定期目标,例如每周更新一篇文章。好的记忆力不如不好的写作。复习通常很重要,避免三天钓鱼和两天晒网。

今天开始分享:

Java简介1.Java的三大系统

jvm教程,jvm简单理解

Java是面向对象编程语言Java和Java平台的总称。 Java有三个系统:

JAVASE(java2平台标准编辑器) Java平台标准版

JAVAEE(java2平台企业编辑器)Java平台企业版

JAVAME(java2 Platform Micro Editor) Java平台标准版

JavaSE 是JavaEE 和JavaME 的基础。

JavaEE建立在JavaSE之上,用于开发B/S处理软件,即开发企业级应用程序。 JavaEE基于JAVASE并对其进行了扩展,包括了许多有用的框架,例如常用的Spring、Struts和Hibernate。 JavaSE 既是一个框架,也是一个规范。 JavaSE 包括您在开发过程中使用的许多组件,例如servlet、EJB、JSP 和JSTL。同时JAVAEE提供了很多标准化的接口,但是没有实现。因此,尽管不同制造商的实现细节可能有所不同,但外部用户会看到统一、标准化的接口。

JavaME是一套专门为嵌入式设备设计的API接口规范,专门用于移动和嵌入式设备软件的开发。

注:我之前已经提到过Android Studio,但是当谈到Android软件开发和JavaME时,据我所知,两者之间的唯一联系是它们都是用Java语言实现的,仅此而已。 Android软件无法在javaME环境中运行。另外,javaME软件无法在Android环境下运行。

2.Java的主要特点

尽管Java语言由于其语法与C和C++类似而很简单,但它也放弃了一些在C++中很少使用的复杂功能,例如运算符重载、多重继承、自动转换和指针丢弃等。分配和重用内存。

Java 音频是面向对象的。 Java Speech 提供面向对象的功能,例如类、接口和继承。然而,Java 类不支持多重继承,而接口则支持。 Java提供了类和接口之间的实现机制。全面的动态绑定支持。

Java语言是分布式的,支持Internet应用程序开发,其网络应用程序编程接口(Java net)提供了支持网络应用程序开发的类库,如URL、URLconnections、Sockets和ServerSockets等。 )机制也是开发分布式应用的重要手段。

Java 语言非常强大。 Java的强类型机制、异常处理和垃圾收集器是保证Java程序健壮性的关键要素。 Java的指针销毁机制很聪明。 Java的安全检查机制使其更加健壮。

Java 语言是安全的,并提供安全机制来防止来自网络的恶意代码的攻击。 Java对通过网络下载的类有安全防范机制(ClassLoader类)、分配不同的命名空间以防止本地类同名替换、字节码检查、安全管理机制(Class SecurityManager)来配置安全卫士。

Java 语言是架构中立的。 Java 程序(.java) 由Java 平台编译为体系结构中立的字节码格式(.class),并且可以在任何实现Java 平台的系统上运行。网络环境和软件分发。

Java语言是可移植的,这种可移植性来自于它的架构中立性。

Java 语言是解释性的。 Java程序在Java平台上被编译成可移植的字节码格式。在运行时,Java平台的Java解释器解释并执行这些字节码。执行时需要的类会在执行时加载到执行环境中。连接过程。

Java 语言是高性能的。与解释型高级脚本语言相比,Java 具有高性能。由于即时(JIT)编译技术的进步,Java的执行速度越来越接近C++。

Java语言是多线程的,Java支持多个线程同时执行,并提供了多线程同步机制。 Thread 是Java 语言中的一个特殊对象,必须由Thread 类或其后代(孙)类创建。

Java 语言是动态的。 Java 语言的设计目标之一是适应动态变化的环境。 Java程序所需的类可以动态加载到执行环境中,也可以通过网络加载所需的类。这对于软件升级很有用。此外,Java 中的类具有运行时表示形式,并且可以执行运行时类型检查。

其实Java的这些主要特性的描述已经包含了很多你需要了解的Java相关的基础知识点。

3、JDK与JRE的关系:

JDK:支持Java程序开发的最小环境。 JDK=Java 编程语言+ Java 虚拟机+ Java API 类库。

JRE:支持运行Java程序的标准环境。 JRE=Java 虚拟机+ Java API 类库的Java SE API 子集。

JVM 我很困惑从哪里开始写有关JVM 的文章,或者我想从这个知识集合中构建哪些概念。

Java技术的核心是Java虚拟机(JVM),所有Java程序都在其中运行。然而,JVM是一个跨语言平台,与语言无关,并且不受Java语言的束缚。任何编程语言的编译结果,包括JVM内部指令、符号表和其他辅助信息,都是可以被虚拟机识别和加载的有效字节码文件。 Java 虚拟机驻留在操作系统之上,不直接与硬件交互。

整个JVM系统包括JVM内存空间、JVM内存溢出、类加载、垃圾回收、性能优化等。您需要了解的有关Java 虚拟机(JVM) 的全部内容就是这篇文章。这篇文章有一个非常完整的思维导图。你还应该从JVM 内存空间、类加载和垃圾收集开始,但我不会深入太多,因为有很多概念性的东西我不完全理解。为了充分理解,稍后您需要进一步了解JVM。

1 JVM内存空间和JVM内存溢出

如图所示,JVM运行时内存空间包括程序计数器、本地方法栈、虚拟机栈、方法区和堆,并且程序计数器、本地方法栈和虚拟机栈是线程隔离的。方法区和堆都是线程。

1.1 程序计数器寄存器

内存空间小,线程是私有的。它是当前线程执行字节码的信号指示器,分支、循环、跳转、异常处理、线程恢复等基本功能都依赖于计数器。当线程正在执行Java方法时,该计数器记录正在执行的虚拟机字节码指令的地址。如果线程正在执行本机方法,则计数器值未定义。程序计数器是Java 虚拟机规范中唯一没有指定OutOfMemoryError 状态的区域。

1.2 虚拟机堆栈(VM Stack)

2.2 类加载过程

2.2.1 负载

a) 找到需要加载的类。使用类的完全限定名称获取定义此类的二进制流(zip 包、网络、操作生成、jsp 生成、数据库读取)。

b) 将类放置在方法区中。将二进制流表示的静态存储结构转换为方法域中的运行时数据结构。

c) 创建访问该类的入口。在内存中创建一个java.lang.Class 对象,该对象表示此类作为访问此类的各种数据结构的入口点。

数组类的一个特点是:虽然数组类不是通过类加载器创建的,而是由虚拟机直接创建的,但是数组类的元素类型最终是由类加载器加载的。

a) 如果数组类的元素是引用类型,则使用类加载来递归加载它们。

b) 如果数组类的元素是值类型,则虚拟机将该数组标记为引导类加载器关联。

c) 数组类的可见性与其元素的可见性相匹配。如果数组类的元素是值类型,则默认情况下该数组类的可见性是公共的。

加载和连接阶段交错执行,并且仅保证在启动时间之前或之后发生。

2.2.2 验证

验证是连接的第一步,主要是保证字节码中包含的信息满足当前虚拟机的要求,主要是文件格式验证、元数据验证,包括字节码验证、符号引用验证。

文件格式验证:文件格式验证直接验证字节流。只有通过文件格式验证的字节流才会存储在方法区中。以下三个验证都是针对方法区的存储结构,并不直接操作流的字节。

元数据验证:进行语义验证,确保不存在不符合Java语言规范的元数据信息。比如这个类有没有父类,父类的继承有没有不规范的地方(final类继承、非抽象类没有实现所有方法等)?

字节码验证:这是整个验证过程中最复杂的部分,其主要目的是通过对数据流和控制流的分析来确定程序的语义是否安全且符合逻辑。通过对方法体的验证和分析,该阶段确保类方法在运行时不会触发危及虚拟机安全的事件。

符号引用验证:当符号引用转换为直接引用时,会发生符号引用验证。这发生在连接的第三阶段,即解决阶段。主要目的是检查类本身以外的信息是否匹配。例如,是否可以通过其完全限定名称找到引用的类,是否可以在指定的类中找到指定的变量和方法,以及是否可以访问这些方法。如果此阶段发生错误,则会抛出java.lang.IncompatibilityClass.changeError 异常的子类,例如java.lang.illegalAccessError、java.lang.NoSuchFiledError 和java.lang.NoSuchMethodError。

2.2.3 准备工作

在这个阶段,我们正式为类分配内存并为变量设置初始值。这里引用的变量包括静态修饰的变量,其他类成员变量是在初始化阶段被赋值的。

不过,这里的初始值是指数据类型的零值,并不是常说的“变量初始化”,比如public static int a=12。将a赋值给12的putstatic指令在编译后存储在程序中。由于它位于.clinit() 方法内部,因此在初始化阶段a 被赋值为12。

特殊情况:ConstantValue 属性的值。

可以看到,用staticfinal修饰的字段在编译时会生成一个ConstantValue属性,ConstantValue值会直接赋给该字段,为类加载做准备,编译时将结果放入常量池中。

public class Test{ public static int a1=12;//在类加载的连接准备阶段,将int 0的零值赋给a1,只有在初始化阶段12才赋给a1 public Final int a2=13 ;//最后修改的字段在运行时初始化,可以直接赋值,也可以在实例构造函数中赋值。分配后无法更改。 public static Final int a3=14;//编译时生成ConstantVlaue属性的值12,并在类加载的连接准备阶段直接将ConstantValue的值赋给a3} 2.2.4 分析

该阶段是虚拟机用直接引用代替符号引用的过程。

符号引用使用一组符号来描述引用的目标。符号可以是任何形式的文字。直接引用是直接指向目标的指针、相对偏移量或间接标识目标的句柄。直接引用与虚拟机的内存布局有关。

解析操作主要对七种类型的符号引用执行:类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用站点修饰符。其中每一个都对应常量池中的七种常量类型。

2.2.5 初始化

前面的过程由虚拟机主导,它启动初始化阶段并执行类中的Java代码。运行clinit() 来初始化类变量和静态代码块。

()方法是由编译器生成的,它自动收集一个类中所有类变量的赋值动作,并合并到静态代码块static{}中的语句。编译器收集它们的顺序由语句的顺序决定。静态语句块只能访问静态语句块之前定义的变量。静态语句块后定义的变量可以在静态语句块内赋值,但不能访问。

2.3 类加载器

获取描述类及其完全限定名称的二进制字节流。

2.3.1 类加载器的类型

对于Java虚拟机来说,只有两个类加载器。一个是启动类加载器(用C++实现,是Java虚拟机的一部分),另一个是类加载器(用Java实现,独立于虚拟机)。 machine)。均继承自java.lang.ClassLoader)

a) 启动类加载器。

加载lib 或-Xbootclasspath 路径下的类

b) 扩展类加载器

将lib/ext 或类加载到java.ext.dirs 系统变量指定的路径中。

c) 应用程序类加载器

ClassLoader加载用户路径指定的类库。

2.3.2 家长委托模型

除了顶层启动类加载器外,所有其他类加载器都有自己的父加载器。

双亲委托模型的工作过程:当类加载器收到类加载请求时,会将请求委托给父类加载器,而不是先单独加载。仅当父类加载器无法尝试时,子类才会尝试。请完成并加载。

2.3.3 破坏性的双亲委派模型

为什么要用父模型,一是安全,二是性能,避免核心类的重复加载和篡改。然而,家长委派模型在三种情况下会崩溃:

第一个损害:JDK 2.0中出现了双亲委托模型,JDK 1.0中出现了类加载器和抽象类java.lang.ClassLoader,因此在双亲委托模型出现之前就已经存在的用户特定数据定义了用户名的类加载器不符合父委托模型。这部分自定义类加载器继承自ClassLoader抽象类,并重写了loadClass()方法。

第二次损害:双亲委派模型本身的缺陷引入了Thread Context ClassLoader,所有涉及Java SPI的加载动作基本上都是线程,如JNDI、JDBC、JCE等。使用上下文加载器,如JAXB或JBI,打破了父委托模型的层级模型。

第三种危害:由于用户不断追求程序动态性而造成的,如代码热替换、模块热部署等。简单来说,不需要重启机器,部署时就可以使用。在OSGI中实现模块热部署的关键是实现自定义类加载器。在OSGI中,类加载器不再具有双亲委托模型的树形结构,而演变为更为复杂的网络结构。

如果需要的话,我们稍后可以了解更多关于第二次和第三次破坏的信息。

3. 垃圾收集3.1 概述

Java虚拟机的程序计数器、虚拟机栈、本地方法栈都是线程私有的,与线程同生共死。堆区和方法区是不同的。程序运行时,加载类、调用方法、创建字段、创建实例对象、分配内存空间……这些操作需要多少内存空间,什么时候进行?都是为了释放空间和回收记忆。直到我运行程序才意识到,在C++中这部分空间是手动管理的,而Java实现了一个垃圾收集器来管理这部分空间。内存空间。

3.2 对象是否已经死亡?

为了正确回收内存,您需要确定哪些对象是“死的”,哪些对象是“活的”。

3.2.1 引用计数算法(引用计数)

在对象的开头维护一个引用计数器,每次向对象添加引用时,该计数器都会增加+1,如果引用丢失,该计数器会增加-1。引用计数器为0 表示该对象已被引用。对象已死。

优点:简单、高效。缺点:无法区分强、软、弱、虚引用的类别,循环引用问题导致锁和内存溢出。

public class A{ /*对于非循环引用*/B b1=new B(); //b1的引用计数器,指向对象B1 counter=1 b1=null; //b1.counter=0,b1指向的对象回收内存/*循环引用*/B b2=new B();//b2 指向对象B2 中的counter=1; B b3=new B();//b3 指向对象B3 中的counter=1; b2. instance=b3 ;//B2的计数器=2;维护两个引用,一个来自b2,一个来自B3。 instance b3.instance=b2;//B3 的计数器; b2=null; //B2 的计数器=1; 维护来自B3 的引用。 instance b3=null; //counter for B3=1; //B2和B3中的空间在程序内将不再可访问,但它们仍然会互相引用并维护一个计数器。=0,如果使用引用计数算法,则这两个存储器不能被回收或使用。 }class B{ public Objectinstance=null;}3.2.2 可达性分析算法(Gc Roots Tracing)

当您使用一组GC Roots 对象作为起点向下搜索时,所经过的路径就变成了引用链。如果没有从一个对象到GC根对象连接的引用链,你就知道该对象不可用。

在可达性分析中标记为不可达的对象并不意味着“死亡”;它们被暂时标记和剔除。 ()方法被放入F-Queue队列中,由虚拟机自动创建的一个低优先级线程来执行它。然后,GC 对F 队列中的对象执行第二次较小的标记。如果此时没有新的关联出现,则基本上被回收了。

在以下情况下,可达性分析算法可以用作GC Roots 对象:

a) 虚拟栈中局部变量表引用的对象

b) 本地方法栈中JNI引用的对象

c) 方法区域中静态变量和常量引用的对象

如图所示,reference1、reference2、reference3有以下三个引用链作为GC根:

参考1——对象实例1

参考2——对象实例2

参考3 -- 对象实例4 -- 对象实例6

对象实例3和对象实例5是本次可达性分析中标记为不可达对象的实例。

3.2.3 引用类型

引用计数方法中有四种类型的引用:强引用、软引用、弱引用和虚引用。

有力的参考

强引用在程序中很常见,比如“Object obj=new Object()”,但只要强引用还存在,垃圾收集器就不会回收所引用的对象。

软参考

软引用描述了一些有用但不是必需的对象。软引用对象在系统溢出之前就包含在回收范围内。

弱引用

弱引用还描述非必要的对象,并且比软引用弱。弱引用的对象会在下次垃圾回收时被回收,无论是否发生内存溢出。

幻象参考

幻像引用(Phantom Reference),也称为幽灵引用或幻像引用,是最弱的引用关系类型。对象是否具有虚拟引用对其生命周期没有影响,并且无法通过虚拟引用获取对象实例。为对象设置虚拟引用关联的唯一目的是在对象被回收时接收系统通知。

3.2.4 回收方法区

可以看到,到目前为止我们主要关注的是堆的垃圾回收,虽然这部分垃圾回收效率更高,但是方法区的垃圾回收效率却远不如这个。

方法区的垃圾收集主要由两部分组成:废弃的常量和不必要的类。

废弃常数的判定:一般判定为没有引用常数。

识别无用的类。

a) 该类的所有实例都已被回收,并且Java堆中没有该类的实例。

b) 加载类的ClassLoader被回收

c) 该类对应的java.lang.Class对象不能通过反射机制被引用或访问。

3.3 内存复用方法3.3.1 标记清除

这是标记需要回收的对象并清除内存中有关这些对象的信息的最简单方法。

缺点:效率低下,产生大量空间碎片。

3.3.2 标记压缩算法:标记-清除-压缩

该算法在标记清除算法之上执行空间压缩和运动重定位处理。压缩空间需要一些时间,这会影响垃圾收集的效率。

3.3.3 复制算法:标记-清除-复制

它将内存分为两个区域,一个区域负责加载常规对象信息,另一个内存区域用于垃圾回收。每当将一个空间中剩余的对象复制到另一个空间时,该空间就会立即被删除。该算法比mark-clear-compression效率更高,但需要两个空间,内存需求较大,内存占用较低,适合短寿命的对象。

3.3.4 分代回收

根据对象生命周期,将对象分为新生代和老年代,并有针对性地使用内存回收算法。

3.3.4.1 新一代

通常,新一代的寿命很短,并且基于标记清除复制算法进行回收。

3.3.4.2 上一代

经过多次垃圾回收后,如果对象仍然存活并且新生代没有足够的空间,则将对象存储在老年代中。

老一代使用标记扫描压缩算法。使用mark和clear回收空间会产生大量的碎片空间(或浮动垃圾)。如果没有足够的老年代碎片空间可供分配,则使用压缩算法。应用程序必须暂停。

3.3.4.2 永久发电

该区域主要存放Java方法区数据和启动类加载器加载的对象,一般不被回收。

4. 总结:我今天就写到这里。今天只是一小部分。还有许多其他内容我没有详细介绍,例如热点、性能优化、双亲委派模型、线程和内存处置。模型等稍后我得去看看。主要是我从别人那里学到的。我是通过口碑来选择的,但是不同的人强调的东西不同。自己写作可以让你建立自己的想法和概念。

今天的Java和JVM知识分享就到这里了。感谢您的观看。

大家交流探讨,该文章若有不正确的地方,希望大家多多包涵。若内容对小伙伴有帮助,帮忙点个赞支持一下哦~~~ 你们的支持就是我创作的动力~

本站涵盖的内容、图片、视频等数据,部分未能与原作者取得联系。若涉及版权问题,请及时通知我们并提供相关证明材料,我们将及时予以删除!谢谢大家的理解与支持!

Copyright © 2023

apse">