英文Max非堆内存怎么翻译?
对JVM的深入了解可以帮助我们提高从平台角度解决问题的能力,比如有效防止内存泄漏、优化线程锁的使用、更高效地收集垃圾、提高系统吞吐量、减少延迟、提高其性能等。
你是怎么理解JVM的?
JVM是JAVA虚拟机的缩写。顾名思义,它是虚拟计算机,是硬件计算机的抽象(虚构)实现,是Java平台的一部分,如图所示(见图底):
JVM是Java程序实现跨平台的基础(Java的跨平台本质上是通过不同平台的JVM实现的)。它的作用是加载Java程序,把字节码翻译成机器码然后交给CPU执行。如图所示:
在程序执行之前,Java代码(。java)应该转换成字节码(。类)。JVM通过ClassLoader将字节码加载到内存中,关注硅谷,轻松学习。但是字节码文件是JVM的一套指令集规范,不能直接交给底层操作系统执行。所以需要一个专门的命令解析器执行引擎,把字节码翻译成底层机器码,然后交给CPU。
市场上有哪些主流的JVM?
JVM是一种规范。基于这个规范,不同的公司做了具体的实现。BEA公司开发JRockit VM?后来在2008年被甲骨文收购;IBM开发了J9 VM?,只在IBM内部使用。Sun公司开发的HotSpot VM?之后2010被甲骨文收购。目前是甲骨文中最主流的JVM虚拟机,也是最常用的。
JVM的架构是什么?
JVM的架构,如图所示:
ClassLoader系统负责将类加载到内存中;运行时数据区负责存储对象数据信息;执行引擎负责调用对象执行业务;本机接口负责为Java集成不同的编程语言。
JVM的运行模式有哪些?
JVM有两种运行模式:服务器和客户端。两种模式的区别在于客户端模式启动较快,服务器模式启动较慢;但是在启动进入稳定期后,服务器模式下的程序运行速度要比客户端快得多。这是因为服务器模式启动的JVM使用了重量级虚拟机,对程序的优化程度更高。以客户机模式启动的JVM使用轻量级虚拟机。所以服务器启动慢,但是稳定后比客户端快很多。
目前64位jdk默认为服务器模式(可以通过java -version查看)。虚拟机在客户端模式下运行时,使用的是轻量级编译器,代码名称为C1,而在服务器模式下启动的虚拟机使用的是相对重量级的编译器,代码名称为c2。c1和C2都是JIT编译器,C2编译比C1编译器更彻底,服役后性能更高。
JVM的运行时内存结构是怎样的?
不同的虚拟机实现可能略有不同,但都遵循Java虚拟机规范,Java 8 virtual。
根据模拟规范,Java虚拟机管理的内存将包括以下区域,如图所示:
Java堆
Java堆是JVM中最大的一块内存,由所有线程共享。它是在虚拟机启动时创建的,主要用来存储对象实例,大部分对象实例也是在这里分配的。随着JIT编译器的发展和转义分析技术的逐渐成熟,栈上分配和标量替换优化的技术将会导致一些微妙的变化,所有对象都分配在堆上将逐渐变得不那么绝对。不转义的小对象也可以直接在堆栈上分配。如果堆中没有内存来完成实例分配,并且堆不能再扩展,系统的底层运行时将抛出OutOfMemoryError。按照Java虚拟机的规范,Java堆可以在物理上不连续的内存空间,只要逻辑上连续,就像我们的磁盘空间一样。在实现上可以是固定大小,也可以是可扩展的,但目前主流的虚拟机都是可扩展的,堆内存大小由-Xmx和-Xms参数定义。
方法区域
Methed Area是一个规范,用于存储由虚拟机加载的数据,如类信息、常量、静态变量、即时编译代码等。不同的jdk,方法区的实现是不同的。热点虚拟机使用本机内存实现JDK 8中的方法区。当方法不能满足内存分配要求时,将引发OutOfMemoryError异常。
Java虚拟机堆栈(VM堆栈)
Java虚拟机堆栈描述了Java方法在执行时的内存模型。每个方法被一个线程调用时,都会创建一个堆栈框架来存储局部变量表、操作数堆栈、动态链接、方法出口等信息。每一个方法从调用到执行完成都讲究硅谷,很容易了解到它对应的是一个栈帧进出虚拟机栈的过程。如果线程请求的堆栈深度大于虚拟机允许的堆栈深度,将引发StackOverflowError异常。如果虚拟机可以动态扩展,并且在扩展过程中无法请求足够的内存,则会引发OutOfMemoryError异常。
JVM本地方法堆栈
原生方法栈的功能和虚拟机栈类似,只是虚拟机栈服务于Java方法,而原生方法栈服务于虚拟机调用原生方法。Java虚拟机规范中对本地方法栈没有特殊要求,虚拟机可以自由实现,所以在Sun HotSpot虚拟机中直接集成了本地方法栈和虚拟机栈。
JVM程序计数器寄存器
程序计数器寄存器是一个很小的内存空间,可以看作是当前线程执行的字节码的行号指示。在虚拟机的概念模型中,字节码解析器的工作就是通过改变这个计数器的值来选择下一条要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基本功能都需要这个计数器来完成。
因为JVM的多线程是通过依次切换线程,分配处理器执行时间来实现的,也就是说,在任何时刻,一个处理器(或者内核)只会在一个线程中执行指令。所以为了在线程切换后恢复正确的执行位置,每个线程都有独立的程序计数器。
如果线程正在执行Java中的方法,程序计数器记录正在执行的虚拟机的字节码指令的地址;如果是原生方法,这个计数器是未定义的,所以这个内存区域是Java虚拟机规范中唯一没有指定OutOfMemoryError的。
如何理解JVM中的GC系统?
跟踪所有还在使用的对象,把剩下的标记为垃圾,然后回收,这个过程叫做GC(垃圾回收)。所有的GC系统都可以从GC(如引用计数、对象可达性分析)、GC收集算法(标记-清除、标记-清除-排序、标记-复制-清除、生成)、GC收集器(如串行、并行)来判断策略。
JVM引用链中的根可以是什么?
Java虚拟机堆栈中的引用对象;
本地方法堆栈中由JNI(通常称为本机方法)引用的对象;
方法区域中类静态常量的引用对象;
方法区域中常量的引用对象。
JVM中常见的垃圾收集算法有哪些?
参考计数器算法
该算法为每个对象设置一个引用计数器。每当有引用这个对象的地方,计数器就加1,反之,每当引用无效,计数器就减1。也就是说,通过计数来判断一个对象是否是垃圾。例如:
引用计数法有一个很大的缺陷就是循环引用,比如:
可达性分析算法
该算法的核心思想是从一系列“GC根”对象为起点进行搜索,搜索路径称为“引用链”。证明了一个对象在没有引用链连接到GC根的情况下是可以回收的。例如:
复制算法
该算法将内存分成两个大小相同的块。当这个块用完后,把当前活的对象复制到另一个块,然后一次性清空当前块。这种算法的缺点是只能使用一半的内存空间。例如:
标记清除算法
该算法的实现分为两个阶段。在第一阶段,从引用根节点开始标记所有被引用的对象,在第二阶段,遍历整个堆以清除未标记的对象。这种算法需要挂起整个应用,同时会产生内存碎片。例如:
标记排序算法
该算法结合了“清除标记”和“复制”算法的优点。第一阶段从根节点开始标记所有被引用的对象,第二阶段遍历整个堆,将存活的对象“压缩”复制到堆的一个空间,然后按顺序排出。该算法避免了“标记-清除”的碎片问题和“复制”算法的空间问题,例如:
JVM对象引用的类型有哪些?
引用计数法和可达性分析算法都与对象的“引用”有关【说说Java中的四类引用。】,可见对象的参照物决定了对象的生死。对象的引用关系如下。
有力的引用
只要强引用存在,像Object obj = new Object()这样在代码中无处不在的引用就永远不会被垃圾收集器回收。
软引用
它是一个相对强的引用,具有较弱的引用,可以使对象免于一些垃圾收集。只有当JVM认为内存不足时,才会尝试回收软引用指向的对象。JVM将确保在抛出OutOfMemoryError之前清除软引用所指向的对象。
弱引用
非本质对象,但是强度比软引用弱,弱引用关联的对象只能存活到下一次垃圾回收。
虚拟参考
也称为ghost引用或phantom引用,是最弱的引用关系,无法通过虚拟引用获得对象实例。为对象设置虚拟引用的目的只是为了在对象被收集器回收时收到系统通知。
JVM垃圾收集器有哪些分类?
新生代取料机
串行、全新、并行扫气
老年回收者
串行旧、并行旧、CMS
整堆取料机
G1垃圾收集器
分代垃圾收集器有哪些组件?
一代垃圾收集器由年轻一代和年老一代组成。默认情况下,新生代和老一代的内存比为1:2。
新一代的组件有哪些?:
新生代由Eden、Form Survivor和To Survivor组成,它们的默认内存比为8:1:1,如图所示:
新一代垃圾收集是如何实现的?
第一步是复制伊甸的活体,从幸存者到幸存者区;第二步将清空Eden和幸存者分区;第三步是将分区从幸存者切换到幸存者(从幸存者切换到幸存者,从幸存者切换到幸存者)。当新一代幸存者分区为2时,空间利用率和程序运行效率都是最优的。
谈谈JVM中的CMS垃圾收集器?
CMS(并发标记和清除)是一个用于并发标记和垃圾清除的收集器。它将使用自由列表来管理内存空间的回收,而不会整理旧的时间。它的优点是标记和清除阶段的大部分工作与应用程序线程同时执行。它可以减少延迟,缩短暂停时间,并提高www.atguigu.com服务的响应时间。当然也有缺陷,主要表现在对CPU资源需求敏感,无法清除浮动垃圾(浮动垃圾是指CMS清除垃圾时用户线程产生的新垃圾,这部分未标记的垃圾称为“浮动垃圾”,只能在下一次GC时清除),而且还会产生大量的空间碎片。
谈JVM中的G1垃圾收集器?
G1(垃圾优先GC)是一个实时收集器,它的设计目标是使STW的暂停时间和分布是可预测和可配置的。可以说是兼顾吞吐量和暂停时间的GC实现。G1可以直观地设置暂停时间的目标。与CMS相比,G1在最好的情况下可能无法延迟CMS的暂停,但在最坏的情况下就好很多了。
使用G1收集器时,Java堆的内存布局与其他收集器有很大不同。它将整个Java堆分成几个大小相等的独立区域。虽然现在还保留着新生代和老年期的概念,但是新生代和老年期已经不是物理屏障了,都是一些(不连续的)区域的集合,比如:
这种划分使得GC不必每次都收集整个堆空间,而是以增量的方式处理,一次只处理一小堆区域的一部分,称为这个收集集。每一次停顿都会收集年轻一代的所有小堆区,也可能只包含老年的一部分小堆区。
G1的另一个创新是估算并发阶段每个小堆中存活对象的总数。构建收集组的原则是首先收集垃圾最多的小堆。这也是G1这个名字的由来:垃圾优先。
G1解决了CMS中的各种难题,包括暂停时间的可预测性,结束了堆内存的碎片化。对于对单个服务延迟非常敏感的系统,G1可以说是HotSpot中最好的选择,尤其是在最新版本的Java虚拟机中,如果CPU资源不受限的话。当然,这种减少延迟的优化并不是没有代价的:G1会有更多的开销,这是由于额外的写屏障和更多的活动守护线程。因此,如果系统是吞吐量优先的,或者如果CPU一直占用100%而不关心单个GC的暂停时间,CMS是更好的选择。
JVM垃圾收集的调优参数有哪些?
-Xmx:512将最大堆内存设置为512m;
-Xms:256初始堆内存(最小堆)为256m
-XX:MaxNewSize设置最大年轻一代内存;
-XX:MaxTenuringThreshold=6设置6个GC后要提升到旧年龄的新生代对象;
-xx: pretnuresizethreshold设置大对象的值,超过这个值的大对象直接进入老一代;
-XX:NewRatio设置分代垃圾收集器的新一代和老一代的内存比例;
-XX:SurvivorRatio设置Eden、Form Survivor和To Survivor在新一代中的比例。
JVM现代并发GC的调优原则是什么?
第一,空间换时间和效率,对于g 1 &;增加ZGC堆内存(更多空闲空间)的配置往往更有利于GC达到目标暂停时间。其次,要知道低停顿不代表高吞吐量。并发GC保证了业务线程仍能同时获得CPU时间片,但也意味着GC会与业务线程抢占计算资源,往往更多的并发阶段为了处理更多的同步问题,会占用更多的计算资源。第三是GC调优要时刻考虑机器资源,对应的系统应用场景等。至少目前没有什么灵丹妙药。
文章来自杰森。