jre是什么(jre安装教程)
序
JVM是Java虚拟机(Java Virtual Machine)的缩写。JVM是计算设备的规范。它是一台虚拟的计算机,是在一台实际的计算机上模拟各种计算机功能而实现的。Java虚拟机包括一组字节码指令集、一组寄存器、一个堆栈、一个垃圾收集堆和一个存储方法域。JVM屏蔽了与具体操作系统平台相关的信息,使得Java程序只需要生成运行在Java虚拟机上的目标代码(字节码),就可以在各种平台上运行,无需修改。JVM在执行字节码的时候,实际上最终把字节码解释为特定平台上的机器指令。
JRE/JDK/JVM之间是什么关系?
JRE(JavaRuntimeEnvironment)是Java平台。所有的Java程序都必须在JRE下运行。普通用户只需要运行开发的java程序,安装JRE即可。
**JDK(java开发工具包)**是程序开发人员用来编译和调试java程序的开发工具包。JDK的工具也是Java程序,也需要JRE来运行。为了保持JDK的独立和完整,JRE也是JDK装置的一部分。因此,在JDK的安装目录下有一个名为jre的目录,用来存储JRE文件。
**JVM(JavaVirtualMachine) * *是JRE的一部分。它是一台虚拟的计算机,是在实际的计算机上模拟各种计算机功能实现的。JVM有自己完善的硬件架构,如处理器、堆栈、寄存器等。,以及相应的指令系统。Java最重要的特点就是跨平台运行。JVM用于支持跨平台实现,与操作系统无关。
Java学习笔记分享地址:JVM调优与实战。400多页的学习笔记
JVM原则
JVM是java的核心和基础,是介于java编译器和os平台之间的虚拟处理器。它是用软件方法实现的抽象计算机。基于较低的操作系统和硬件平台,java字节码程序可以在其上执行。
添加描述
java只要面向JVM,就能生成JVM能理解的代码或字节码文件。Java源文件被翻译成字节码程序,每条指令被运行在特定平台上的JVM翻译成不同平台的机器码。
JVM体系结构
添加描述
ClassLoader(用于加载。类文件)
执行引擎(执行字节码,或执行本地方法)
运行时数据区(方法区、堆、java堆栈、PC寄存器、本地方法堆栈)
JVM运行时数据区
添加描述
第一个模块:PC寄存器
PC寄存器用于存储每个线程在下一步要执行的JVM指令。如果该方法是本地的,则PC寄存器中不会存储任何信息。
第二块:JVM栈
JVM栈是线程私有的,每个线程同时创建一个JVM栈。JVM堆栈存储当前线程中局部基本类型的变量(java中定义的八种基本类型:boolean、char、byte、short、int、long、float、double)、部分返回结果和堆栈帧。非基本类型的对象在JVM栈上只存储一个指向栈的地址。
块3:堆
它是JVM用来存储对象实例和数组值的区域。可以认为这里分配了Java中new创建的所有对象的内存,堆中对象的内存需要等待GC回收。
添加描述
(1)堆是JVM中所有线程共享的,所以上面的对象内存分配需要加锁,这也导致了新对象的开销相对较高。
(2)为了提高对象内存分配的效率,Sun Hotspot JVM会给创建的线程分配一个独立的空 TLAB(线程本地分配缓冲区),其大小由JVM根据运行情况计算,分配对象时无需锁定TLAB。因此,JVM在分配线程的对象时,会尽力分配TLAB上的内存。在这种情况下,JVM中分配对象内存的性能基本上和C一样高效,但如果对象过大,仍然直接使用heaps 空之间的分配。
(3) TLAB只在新一代的Eden空间上工作,所以在编写Java程序时,分配多个小对象通常比大对象更高效。
(4)所有新创建的对象都将存储在新一代Yong代中。如果年轻一代的数据在一个或多个GC后存活,它将被转移到老一代。新对象总是在伊甸园空间中被创建。
第四块:方法区。
①在孙,这一带对应永久世代,也称永久世代。
(2)方法区存储信息(名称、修饰符等。)类、类中的静态变量、类中定义为最终类型的常数、类中的字段信息以及类中的方法信息。开发者在程序中通过类对象中的getName、isInterface等方法获取信息时,这些数据都来自方法区,方法区是全局共享的。在一定条件下,它也会是GC,当方法区域需要的内存超过其允许的大小时,它会抛出OutOfMemory错误消息。
第五块:运行时常量池。
存储为类中的固定常数信息、方法和字段的引用信息等。,它的空是从方法区域分配的。
块6:本地方法堆栈
JVM采用本地方法栈来支持本地方法的执行,这个区域用来存储每个本地方法调用的状态。
一种确定物体“死亡”的算法
因为程序计数器、Java虚拟机栈、本地方法栈都是线程独占的,所以它们占用的内存是随线程而生,随线程结束而恢复。但是,Java堆和方法区不同,线程共享是GC的唯一部分。
堆里几乎都是对象。在GC之前,需要考虑哪些对象还活着不能回收,哪些对象死了可以回收。
有两种算法来确定一个对象是否是活的:
1.)引用计数算法:给对象添加一个引用计数器。每当一个对象被应用到一个地方,计数器就加1;当参考失败时,计数器减1;当计数器为0时,表示对象已经死亡,可以回收。但是,很难解决两个对象之间的循环引用问题。
2.)可达性分析算法:以一系列被称为“GC根”的对象为起点,搜索所遵循的路径称为引用链。当一个对象在没有任何引用链的情况下连接到GC根时(即对象对于GC根是不可达的),证明该对象是死的,可回收的。Java中可以作为GC根的对象包括:虚拟机栈中引用的对象、本地方法栈中本机方法引用的对象、方法区中静态属性引用的对象、方法区中常量引用的对象。
在主流商业编程语言(比如我们的Java)的主流实现中,可达性分析算法是用来判断一个对象是否有生命的。
JVM垃圾收集
垃圾收集的基本原理是回收内存中不再使用的对象。气相色谱中用于回收的方法称为收集器。由于GC需要消耗一些资源和时间,Java在分析对象的生命周期特征后,按照新的一代和旧的一代来收集对象,以尽可能缩短GC造成的应用暂停。
(1)新生代天体的集合称为小GC;;
(2)老一代的对象集合称为全GC;;
(3)程序中主动调用System.gc()强制执行的gc是全GC。
GC会采用不同的方法回收不同类型的对象引用,JVM对象的引用可以分为四种:
(1)强引用:默认情况下,所有对象都采用强引用(只有在使用GC时,如果没有其他对象的引用,这个对象的实例才会被回收)。
(2)软引用:软引用是Java提供的应用,更适合缓存场景(只有内存不够的时候才会GC)。
(3)弱引用:在GC的时候会被GC回收。
(4)虚引用:因为虚引用只是用来知道对象是不是GC。
垃圾收集算法
1.标记清除算法
最基本的算法分为两个阶段:标记和清除:首先标记需要回收的对象,标记后统一回收所有被标记的对象。
它有两个缺点:一是效率,标记和清除过程效率低;一个是空之间的问题。清除标志后会产生大量不连续的内存碎片(类似于我们电脑的磁盘碎片)。空之间碎片太多会导致需要分配大对象时找不到足够的连续内存,所以不得不提前触发另一个垃圾收集动作。
添加描述
复制算法
为了解决效率问题,出现了一种“复制”算法,将可用内存按照容量分成两个相等的块,每次只需要使用其中一个。当一个内存块用完时,将幸存的对象复制到另一个块,然后立刻清理新使用的内存空。这样解决了内存碎片问题,但代价是可用内容减少到原来的一半。
添加描述
标记排序算法
当对象存活率较高时,复制算法会进行频繁的复制操作,效率会降低。所以就有了标记-排序算法。标记过程与标记-清除算法相同,但在后续步骤中,不是直接清除对象,而是将所有存活的对象移到一边,然后直接清除结束边界外的内存。
添加描述
世代收集算法
目前商用虚拟机的GC采用分代收集算法。这个算法没有什么新意,只是根据对象生命周期的不同,把堆分为新生代和老一代。方法区称为永久生成(新版本中已经抛弃了meta 空的概念,永久生成使用JVM内存,而meta 空直接使用物理内存)。
这样就可以根据不同年龄段的特点,采用不同的采集算法。
添加描述
新生代,物体“早晚死”。每一次GC,都会有大量的对象死亡,少数存活下来。使用复制算法。分为伊甸区和新生代幸存者区(幸存者from,幸存者to),大小比例默认为8:1:1。
因为旧对象存活率高,没有额外的空分发保证,所以使用标记-清除或标记-排序算法。
新生成的对象首先进入伊甸园区域。当伊甸园区满了,幸存者再次被使用。当Survivor from也已满时,会执行次要GC(新一代GC ),将Eden和Survivor from中的幸存对象复制到Survivor to中。然后清除空伊甸园和幸存者。此时,原来的幸存者从成为新的幸存者到,原来的幸存者到成为新的幸存者从。复制时,如果Survivor to不能容纳所有存活的对象,则按照老年的分配担保(类似于银行的贷款担保)将对象复制到老年中。如果老年不能容纳他们,将进行全GC(老年GC)。
对象直接进入老年:JVM中有一个参数配置。
-xx: pretenuresezethreshold,使大于该设置的对象直接进入老年,以避免Eden和Survivor区域之间的大量内存拷贝。
长寿对象进入老年期:JVM为每个对象定义了一个对象年龄计数器。如果该对象在Eden出生并通过第一个次要GC后仍然活着,并且可以被Survivor容纳,则它将被移入Survivor,其年龄将被设置为1。如果你一次都没有从轻微GC中幸存,你将增加你的年龄1。当他的年龄达到一定程度(默认为15,可以通过XX:MaxTenuringThreshold设置)时,他就会转入老年。但是,JVM并不总是要求年龄必须达到最大年龄才能提升到老年。如果Survivor 空中所有同龄(如x岁)的对象之和大于Survivor大小的一半,则所有x岁以上的对象将直接进入老年,而无需等待最大年龄要求。
垃圾收集工
垃圾收集算法是方法论,垃圾收集器是具体实现。JVM规范没有任何关于如何实现垃圾收集器的规则,所以不同厂商和不同版本的虚拟机提供的垃圾收集器差别很大。这里我们只看热点虚拟机。
JDK7/8之后,热点虚拟机的所有收集器和组合(连接)如下:
添加描述
串行收集器
串行收集器是最基础也是最古老的收集器,曾经是新一代手机的唯一选择。他是单线程的,只用一个CPU或者一个收集线程来完成垃圾收集。当它收集的时候,必须挂起所有其他工作线程,直到它结束,也就是“停止世界”。停止所有用户线程对于许多应用程序来说是不可接受的。比如你正在做一件事,被别人逼停了,你还能指望羊驼从你心里冲过吗?
尽管如此,它仍然是运行在客户端模式下的虚拟机默认的新一代收集器:简单高效(相比其他收集器的单线程,因为没有线程切换等开销。).
工作图:
添加描述
Par收集器
PAR collector是串行收集器的多线程版本。除了多线程,其他行为(收集算法,停止世界,对象分配规则,回收策略等。)与串行收集器相同。
在许多运行在服务器模式下的JVM中,它是新一代收集器的首选。其中一个很重要的原因是,除了串行,只有它可以与旧的CMS收集器。
工作图:
添加描述
平行花葶收集器
新一代采集器,并行多线程采集器。它的目标是达到一个可控的吞吐量(即CPU运行用户代码所花费的时间与CPU总消耗时间的比值,即吞吐量=用户代码行所花费的时间/垃圾收集所花费的时间),能够高效利用CPU时间,尽快完成程序的运行任务。适合没有太多交互的后台操作。
串行收集器
旧版本的串行红豆博客收集器,单线程,和“标签排序”算法,主要用于客户端模式的虚拟机。
此外,在服务器模式下:
在JDK 1.5之前,雨水平行扫气收集器一起使用。
作为CMS的后台解决方案,使用
工作图:
添加描述
平行旧收集器
老版本的并行清除,多线程,“标记整理”算法,JDK 1.6刚刚出现。在此之前,并行清除只能用于串行旧的。因为串行老性能差,并行扫气的优势发挥不出来,尴尬~ ~
随着并行旧收集器的出现,“吞吐量优先”收集器终于有了名副其实的组合。当吞吐量和CPU敏感时,可以使用并行清除/并行旧组合。该组合的工作原理图如下:
添加描述
CMS收集器
CMS(Concurrent Mark Sweep)收集器是一种以获得最短恢复暂停时间为目标的收集器,暂停时间短,用户体验好。
基于“标记清除”算法,具有并发收集、低停顿、操作过程复杂的优点,分为四个步骤:
_1)初始标记:_只标记GC根可以直接关联的对象,速度很快,但是需要“停止世界”。
_2)并发标记:_是跟踪引用链的过程,可以和用户线程并发执行。
_3)重新标记:_在并发标记阶段由于用户线程的持续运行而导致标记发生变化的那部分对象的标记记录被修改,比初始标记时间长但远短于并发标记时间,需要“停止世界”
_4)并发清除:_清除标记为可回收并可与用户线程并发执行的对象。
一般来说,CMS收集器的内存回收过程和用户线程是并发执行的,因为在整个过程中占用时间最长的并发标记和并发清理可以和用户线程一起工作。
工作图:
添加描述
CSM收集器有三个缺点:
1)对CPU资源非常敏感
并发不会挂起用户线程,但是它会降低应用程序的速度并减少总吞吐量,因为它会占用一些CPU资源。
CMS的默认收集线程数=(CPU数3)/4;当CPU数量超过4个时,收集线程占用的CPU资源超过25%,可能会对用户程序造成很大影响;当数量小于4时,影响会更大,可能无法接受。
2)无法处理浮动垃圾(用户线程的新红豆博客在并发清理时产生的垃圾称为浮动垃圾),“Conc红豆博客当前模式失败”可能会失败。
并发清理的时候要预留一定的内存空,所以不能像其他旧时代的收集者一样,几乎填满后再收集;如果CMS预留内存空不能满足程序的需要,就会出现“并发模式失败”故障;此时JVM启用备份计划:临时启用Serail旧收集器,导致另一个完整GC的生成;
**3)产生大量内存碎片:**CMS基于“标记-清除”算法,清除后未经压缩产生大量不连续的内存碎片。这将导致在分配大内存对象时无法找到足够的连续内存,因此需要提前触发另一个全GC动作。
G1收藏家
G1(垃圾优先)是JDK7-u4正式商用推出的收集器。G1是服务器端应用程序的垃圾收集器。它的任务是在未来取代CMS收集器。
G1收集器特征:
并行性和并发性:可以充分利用多CPU、多核环境的硬件优势,缩短停顿时间;并且可以与用户线程同时执行。
* *代收集:**G1可以独立管理整个堆,不需要其他GC收集器的配合,以不同的方式处理新对象和已经存活一段时间的对象。
**空整合:**整体采用标记算法,局部采用复制算法(两个区域之间)。不会出现内存碎片,也不会因为大型对象找不到足够的连续空空间而提前触发GC,比CMS collector要好。
* *可预测暂停:* *除了追求低暂停,还可以建立可预测暂停时间模型,让用户明确指定在一个长度为M毫秒的时间段内,垃圾收集所花费的时间不得超过N毫秒,优于CMS collector。
为什么可以实现可预测的暂停?
因为可以有计划地避免整个Java堆的垃圾收集。
G1把记忆的概念分成大小相等的独立区域,新生期和老年期,但它不再是物理上孤立的。
G1跟踪每个区域以获得其收藏价值,并在后台维护优先级列表;
根据每次允许的收集时间,优先回收值最大的区域(名字垃圾优先的起源);
这就保证了在有限的时间内,收集效率可以尽可能的高。
如果该对象被另一个区域中的对象引用怎么办?
判断一个对象是否活的时候,是否需要扫描整个Java堆才能保证准确性?在其他几代收藏家身上,也有这样的问题(G1更突出):新一代回收的时候要扫描旧的?无论G1还是其他代收集器,JVM都使用记忆集来避免全局扫描:每个区域都有一个对应的记忆集;每次写入引用类型数据时,都会产生一个写屏障临时中断操作;然后检查要写入的引用所指向的对象是否与引用类型数据在不同的区域(其他收集器:检查陈年对象是否引用新生代对象);如果不同,则通过CardTable将相关的引用信息记录在引用指向对象的区域所对应的记忆集中;在进行垃圾收集时,在GC根节点的枚举范围中加入记忆集,可以保证不会出现全局扫描和遗漏。
代替计算维护记忆集的操作,恢复过程可以分为四个步骤(类似于CMS):
1)初始标记:只标记能和GC根直接相关的对象,修改TAMS的值(标记开始时的下一个Top),以便下一阶段用户程序并发运行时,在正确可用的区域创建一个新的对象,需要“停止世界”。
2)并发标记:从GC根开始,进行可达性分析,找出幸存的对象,耗时较长,可与用户线程并发执行。
3)最终标记:在并发标记阶段,对由于用户线程的持续运行而导致标记发生变化的对象部分的标记记录进行修正。并发标记时,虚拟机在线程记忆集日志中记录对象更改。在最终标记阶段,将记忆集日志整合到记忆集,比初始标记时间长,但远短于并发标记时间,因此需要“停止世界”。
4)筛选回收:首先对各个区域的回收价值和成本进行排序,然后根据用户预期的GC暂停时间定制回收计划,最后根据计划回收一些区域内的高价值垃圾对象。回收时,使用复制算法将幸存对象从堆上的一个或多个区域复制到另一个空区域,在此过程中压缩和释放内存;它可以并发执行,从而减少暂停时间并增加吞吐量。
工作图:
添加描述
基本结构
从Java平台的逻辑结构上,我们可以从下图来理解JVM:
从上图我们可以清楚的看到Java平台包含的逻辑模块,也知道了JDK和JRE的区别。
最后
分享一张jvm知识图,请喜欢(或转发)给蟹蟹。
此外还整理了40多套PDF文档:全套Java访谈书,七个访谈栏目如《性能调优微服务架构并发编程开源框架分发》,包括Tomcat、JVM、MySQL、SpringCloud、SpringBoot、Dubbo、Concurrency、Spring、SpringMVC、MyBatis、Zookeeper、Ngnix、Kafka、MQ、Redis、MongoDB。如果你对此感兴趣,边肖可以免费分享。
如何获取资料:边肖转发文章私信【面试问题】获取以上资料~
重要的事情说三遍,转发转发,一定要记得转发!!!