
JVM
文章平均质量分 53
Tracker_85
这个作者很懒,什么都没留下…
展开
-
垃圾收集器
垃圾收集器的分类按线程数分,可以分为串行垃圾回收器和并行垃圾回收器。串行回收指的是在同一时间段内只允许一个CPU用于执行垃圾回收操作,此时工作线程被暂停,直至垃圾收集工作结束。串行回收默认应用在客户端的Client模式下的JVM中。并行回收可以运用多个CPU同时执行垃圾回收,提升了应用的吞吐量,和串行回收一样,采用独占式,使用“Stop the World”机制。按照工作模式分,可以分为并发式垃圾回收器和独占式垃圾回收器。并发式垃圾回收器与应用程序线程交替工作,以尽可能减少应用程序的原创 2021-12-06 09:51:35 · 223 阅读 · 0 评论 -
垃圾回收相关概念补充
1.System.gc()的理解在默认情况下,通过System. gc ()或者Runtime . getRuntime() .gc()的调用,会显式触发Full GC, 同时对老年代和新生代进行回收,尝试释放被丢弃对象占用的内存。然而System. gc()调用附带 一个免责声明,无法保证对垃圾收集器的调用,即只提醒JVM希望进行一次垃圾回收,是否立马进行GC由JVM决定。JVM实现者可以通过System. gc ()调用来决定JVM的GC行为。而一般情况下,垃圾回收应该是自动进行的,无须手动触发原创 2021-12-04 20:09:06 · 524 阅读 · 0 评论 -
垃圾回收相关算法之垃圾清除阶段的算法
标记-清除(Mark-Sweep)算法背景:标记一清除算法(Mark-Sweep)是一种非常基础和常见的垃圾收集算法,该算法被J .McCarthy等人在1960年提出并并应用于Lisp语言。执行过程:当堆中的有效内存空间(available memory) 被耗尽的时候,就会停止整个程序(也被称为stop the world) ,然后进行两项工作,第一项则是标记,第二项则是清除。1.标记:Collector从引用根节点开始遍历,标记所有被引用的对象。一般是在对象的Header中记录为可达对象。原创 2021-12-03 15:31:11 · 145 阅读 · 0 评论 -
对象的finalization机制
finalization机制:Java语言提供了对象终止(finalization) 机制来允许开发人员提供对象被销毁之前的自定义处理逻辑。当垃圾回收器发现没有引用指向一个对象,即:垃圾回收此对象之前,总会先调用这个对象的finalize()方法。finalize()方法允许在子类中被重写,用于在对象被回收时进行资源释放。通常在这个方法中进行一些资源释放和清理的工作,比如关闭文件、套接字和数据库连接等。永远不要主动调用某个对象的finalize()方法,应该交给垃圾回收机制调用。理由包括下面三点:原创 2021-12-03 09:18:21 · 85 阅读 · 0 评论 -
垃圾回收相关算法之垃圾标记阶段的算法
垃圾标记阶段的算法垃圾标记阶段:判断对象是否存活在堆里存放着几乎所有的Java对象实例,在GC执行垃圾回收之前,首先需要区分出内存中哪些是存活对象,哪些是已经死亡的对象。只有被标记为己经死亡的对象,GC才会在执行垃圾回收时,释放掉其所占用的内存空间,因此这个过程我们可以称为垃圾标记阶段。那么在JVM中究竟是如何标记一个死亡对象呢?简单来说,当一个对象已经不再被任何的存活对象继续引用时,就可以宣判为已经死亡。判断对象存活一般有两种方式:引用计数算法和可达性分析算法。引用计数算法(referenc原创 2021-12-02 16:05:50 · 184 阅读 · 0 评论 -
垃圾回收概述
关于垃圾收集有三个经典问题:1.哪些内存需要回收?2.什么时候回收?3.如何回收?什么是垃圾呢?垃圾是指在运行程序中没有任何指针指向的对象,这个对象就是需要被回收的垃圾。为什么需要GC?对于高级语言来说,一个基本认知是如果不进行垃圾回收,内存迟早都会被消耗完,因为不断地分配内存空间而不进行回收,就好像不停地生产生活垃圾而从来不打扫一样。除了释放没用的对象,垃圾回收也可以清除内存里的记录碎片。碎片整理将所占用的堆内存移到堆的一端,以便JVM 将整理出的内存分配给新的对象。随着应用程序所应付原创 2021-12-02 14:17:25 · 79 阅读 · 0 评论 -
String以及intern()的使用
String的基本特性String:字符串,使用- -对""引起来表示。String声明为final的,不可被继承String实现了Serializable接口:表示字符串是支持序列化的。 实现了Comparable接口:表示String可以比较大小String在jdk8及以前内部定义了final char[] value用 于存储字符串数据。jdk9时改为byte[]。基于String的相关类也做了一定的修改:AbstractStringBuilder、StringBuffe原创 2021-11-30 19:26:51 · 327 阅读 · 0 评论 -
HotSpot设置模式_C1与C2编译器
HotSpot VM设置程序执行方式缺省情况下HotSpot VM是采用解释器与即时编译器并存的架构,当然开发人员可以根据具体的应用场景,通过命令显式地为Java虚拟机指定在运行时到底是完全采用解释器执行,还是完全采用即时编译器执行。如下所示:➢-Xint: 完全采用解释器模式执行程序; .➢-Xcomp: 完全采用即时编译器模式执行程序。如果即时编译出现问题,解释器会介入执行。➢-Xmixed:采用解释器+即时编译器的混合模式共同执行程序。示例:HotSpot VM中JIT分类在HotSp原创 2021-11-30 15:35:05 · 582 阅读 · 0 评论 -
解释器与JIT编译器
解释器工作机制解释器真正意义上所承担的角色就是一个运行时“翻译者”,将字节码文件中的内容“翻译”为对应平台的本地机器指令执行。当一条字节码指令被解释执行完成后,接着再根据PC寄存器中记录的下一条需要被执行的字节码指令执行解释操作。解释器分类在Java的发展历史里,一共有两套解释执行器,即古老的字节码解释器、现在普遍使用的模板解释器。字节码解释器在执行时通过纯软件代码模拟字节码的执行,效率非常低下。而模板解释器将每一条字节码和一个模板函数相关联,模板函数中直接产生这条字节码执行时的机器码原创 2021-11-30 14:26:20 · 1443 阅读 · 0 评论 -
Java代码编译和执行的过程
Java代码编译和执行的过程大部分的程序代码转换成物理机的目标代码或虛拟机能执行的指令集之前,都需要经过上图中的各个步骤。解释型语言走绿色路径,编译型语言走蓝色路径。对于Java语言:程序源码到抽象语法树过程由javac完成,生成一个字节码文件。javac可以理解为前端编译器。Java字节码的执行是由JVM执行引擎来完成,Java语言是半编译半解释型语言。其中,JIT编译器可以理解为后端编译器。字节码:字节码是一种中间状态(中间码)的二进制代码(文件),它比机器码更抽象,需要直译器原创 2021-11-30 10:40:59 · 389 阅读 · 0 评论 -
执行引擎的作用及工作流程
执行引擎概述执行引擎是Java虚拟机核心的组成部分之一。“虚拟机”是-一个相对于“物理机”的概念,这两种机器都有代码执行能力,其区别是物理机的执行引擎是直接建立在处理器、缓存、指令集和操作系统层面上的,而虛拟机的执行引擎则是由软件自行实现的,因此可以不受物理条件制约地定制指令集与执行引擎的结构体系,能够执行那些不被硬件直接支持的指令集格式。JVM的主要任务是负责装载字节码到其内部,但字节码并不能够直接运行在操作系统之上,因为字节码指令并非等价于本地机器指令,它内部包含的仅仅只是一些能够被JVM所识别原创 2021-11-30 08:53:29 · 188 阅读 · 0 评论 -
直接内存(方法区位置)的简单了解
直接内存概述不是虛拟机运行时数据区的一部分, 也不是《Java虚拟机规范》中定义的内存区域。直接内存是在Java堆外的、直接向系统申请的内存区间。来源于NIO,通过存在堆中的DirectByteBuffer操作Native内存通常,访问直接内存的速度会优于Java堆。即读写性能高。➢因此出于性能考虑,读写频繁的场合可能会考虑使用直接内存。➢Java的NIO库允许Java程序使用直接内存,用于数据缓冲区也可能导致OutOfMemoryError:Direct buffer memory异常由原创 2021-11-29 17:28:16 · 246 阅读 · 0 评论 -
对象访问定位
对象访问定位要点图示1:对象访问定位图示2:句柄访问图示3:直接指针原创 2021-11-29 16:30:48 · 80 阅读 · 0 评论 -
对象的内存布局
内存布局要点:图示:原创 2021-11-29 15:40:47 · 89 阅读 · 0 评论 -
对象的实例化
创建对象的方式newClass的newInstance():反射的方式,只能调用空参的构造器,权限必须是public。Constructor的newInstance(Xxx):反射的方式,可以调用空参、带参的构造器,权限没有要求。使用clone():不调用任何构造器,当前类需要实现Cloneable接口,实现clone()方法。使用反序列化:从文件或网络中获取一个对象的二进制流第三方库Objenesis创建对象的步骤说明 :步骤一,判断类是否加载 :虚拟机遇到一条new指令,首先会原创 2021-11-29 11:52:15 · 164 阅读 · 0 评论 -
字符串常量池为什么要调整?
jdk7中将字符串常量池放到了堆空间中。因为永久代(方法区)的回收效率很低,在full gc的时候才会触发。而full gc是老年代的空间不足、永久代不足时才会触发。这就导致字符串常量池回收效率不高。而我们开发中会有大量的字符串被创建,回收效率低,会导致永久代内存不足。放到堆里,能及时的回收内存。...原创 2021-11-27 18:17:22 · 145 阅读 · 0 评论 -
内存泄露与内存溢出
内存泄露:指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。可以理解为:内存使用完后未归还。内存泄漏积累过多后就会造成内存溢出。举例:单例模式、各种连接完成后未释放 、变量不合理的作用域…本质都是不使用的对象持续占用内存或未被及时回收。内存溢出:是指程序在申请内存时,没有足够的内存空间供其使用。当发生内存溢出时,虚拟机会报OOM 的错误。发生内存溢出的三个地方:虚拟机栈、堆区、方法区...原创 2021-11-27 18:09:21 · 138 阅读 · 0 评论 -
方法区的垃圾回收
有些人认为方法区(如HotSpot虚拟机中的元空间或者永久代)是没有垃圾收集行为的,其实不然。《Java 虚拟机规范》对方法区的约束是非常宽松的,提到过可以不要求虚拟机在方法区中实现垃圾收集。事实上也确实有未实现或未能完整实现方法区类型卸载的收集器存在(如JDK 11时期的ZGC收集器就不支持类卸载)。一般来说这个区域的回收效果比较难令人满意,尤其是类型的卸载,条件相当苛刻。但是这部分区域的回收有时又确实是必要的。以前Sun公司的Bug列表中,曾出现过的若干个严重的Bug就是由于低版本的HotSpot虚.原创 2021-11-27 17:47:01 · 97 阅读 · 0 评论 -
方法区的演进细节
首先明确:只有HotSpot虚拟机才有永久代。其他虚拟机是不存在永久代的概念 。HotSpot中 方法区的变化:版本变化jdk1.6及以前有永久代(占用JVM内存),静态变量存放在永久代里,字符串常量池在运行时常量池中jdk1.7有永久代,但已经逐步“去永久代”,字符串常量池、静态变量移出,保存在堆中jdk1.8及以后无永久代,类型信息、字段、方法、运行时常量池保存在本地内存的元空间,但字符串常量池、静态变量仍在堆中永久代为什么被元空间替换 ?(1)为永.原创 2021-11-27 17:28:56 · 443 阅读 · 0 评论 -
方法区的内部结构
方法区内存储什么?它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等。类型信息:对每个加载的类型(类class、接口interface、枚举enum、注解annotation) ,JVM必须在方法区中存储以下类型信息:①这个类型的完整有效名称(全名=包名.类名)②这个类型直接父类的完整有效名(对于interface或是java . lang.object,都没有父类)③这个类型的修饰符(public, abstract, final的某个子集)④这个类型直接接口原创 2021-11-27 16:59:21 · 256 阅读 · 0 评论 -
方法区的基本理解
方法区的位置方法区是一块独立于Java堆的内存空间。在HotSpot虚拟机中,方法区有一个别名:Non-heap(非堆)。JDK8后,也叫作元空间。概述方法区(Method Area)与Java堆一样, 是各个线程共享的内存区域。方法区在JVM启动的时候被创建,并且它的实际的物理内存空间中和Java堆区一样都可以是不连续的。方法区的大小,跟堆空间一样,可以选择固定大小或者可扩展。方法区的大小决定了系统可以保存多少个类,如果系统定义了太多的类,导致方法区溢出,虚拟机同样会抛出内存溢出错:java原创 2021-11-27 14:54:00 · 725 阅读 · 0 评论 -
堆是分配对象存储的唯一选择吗?
堆是分配对象存储的唯一选择吗?在《深入理解Java虚拟机》中关于Java堆内存有这样一段描述:随着JIT编译期的发展与逃逸分析技术逐渐成熟,栈上分配、标量替换优化技术将会导致一些微妙的变化,所有的对象都分配到堆上也渐渐变得不那么“绝对”了。在Java虚拟机中,对象是在Java堆中分配内存的,这是一个普遍的常识。但是,有一种特殊情况,那就是如果经过逃逸分析(Escape Analysis) 后发现,一个对象并没有逃逸出方法的话,那么就可能被优化成栈上分配。这样就无需在堆上分配内存,也无须进行垃圾回收了。原创 2021-11-26 17:58:20 · 140 阅读 · 0 评论 -
堆空间的参数设置
官方文档 :https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html-XX: +PrintFlagsInitial :查看所有的参数的默认初始值-XX:+PrintFlagsFinal : 查看所有的参数的最终值(可能会存在修,不再是初始值)。 具体 查看某个参数的指令:①jps:查看当前运行中的进程 ②jinfo -flag SurvivorRation(某个参数) 进程id-Xms: 初始堆空间内存(默认为物理.原创 2021-11-26 15:53:12 · 225 阅读 · 0 评论 -
对象的分配过程与垃圾回收过程
为新对象分配内存是一件非常 严谨和复杂的任务,JVM的设计者们不仅需要考虑内存如何分配、在哪里分配等问题,并且由于内存分配算法与内存回收算法密切相关,所以还需要考虑GC执行完内存回收后是否会在内存空间中产生内存碎片。Minor GC(YGC):new的对象先放伊甸园区。此区有大小限制。当伊甸园的空间填满时,程序又需要创建对象,JVM的垃圾回收器将对伊甸园区进行垃圾回收(Minor GC),将伊甸园区中的不再被其他对象所引用的对象进行销毁。再加载新的对象放到伊甸园区然后将伊甸园中的上次未被回收的对象原创 2021-11-26 12:15:13 · 289 阅读 · 0 评论 -
年轻代与老年代
年轻代与老年代概述存储在JVM中的Java对象可以被划分为两类:(1)一类是生命周期较短的瞬时对象,这类对象的创建和消亡都非常迅速。(2)另外一类对象的生命周期却非常长,在某些极端的情况下还能够与JVM的生命周期保持一致。Java堆区进一步细分的话,可以划分为年轻代和老年代。其中年轻代又可以划分为Eden空间、Survivor0空间和Survivor1空间(有时也叫from区、to区)。参数配置配置新生代与老年代在堆结构的占比:(1)默认-XX:NewRatio=2,代表新生代占1,老年原创 2021-11-26 09:46:03 · 109 阅读 · 0 评论 -
设置堆内存大小与OOM
设置堆空间的大小Java堆区用于存储Java对象实例,那么堆的大小在JVM启动时就已经设定好了,可以通过选项" -Xmx"和"-Xms"来进行设置。➢“-Xms"用于表示堆区(新生代+老年代)的起始内存,等价于-XX: InitialHeapSize➢“-Xmx" 则用于表示堆区的最大内存,等价于-XX : MaxHeapSize一旦堆区中的内存大小超过“-Xmx"所指定的最大内存时,将会抛出OutOfMemoryError异常。通常会将-Xms 和-Xmx两个参数配置相同的值,其目的是为了能够原创 2021-11-25 19:20:17 · 370 阅读 · 0 评论 -
堆的细分内存结构
堆的细分内存结构注:永久代或元空间是方法区的具体实现堆的内部结构原创 2021-11-25 16:59:52 · 93 阅读 · 0 评论 -
堆空间的概述
堆的核心概述一个JVM实例只存在一个堆内存,堆也是Java内存管理的核心区域。Java堆区在JVM启动的时候即被创建,其空间大小也就确定了。是JVM管理的最大一块内存空间。堆内存的大小是可以调节的。《Java虚拟机规范》规定,堆可以处于物理上不连续的内存空间中,但在逻辑上它应该被视为连续的。所有的线程共享Java堆,在这里还可以划分线程私有的缓冲区(Thread Local Allocation Buffer, TLAB)。《Java虚拟机规范》中对Java堆的描述是:所有的对象实例以及数组都应原创 2021-11-25 16:01:14 · 534 阅读 · 0 评论 -
本地方法栈
本地方法栈Java虚拟机栈用于管理Java方法的调用,而本地方法栈用于管理本地方法的调用。本地方法栈,也是线程私有的。允许被实现固定或者是可动态扩展大小的内存大小。(在内存溢出方面是相同的)本地方法是使用C语言实现的。它的具体做法是Native Method Stack中登记native方法,在Execution Engine 执行时加载本地方法库。当某个线程调用一个本地方法时,它就进入了一个全新的并且不再受虚拟机限制的世界。它和虚拟机拥有同样的权限。(1)本地方法可以原创 2021-11-24 18:42:42 · 371 阅读 · 0 评论 -
本地方法接口
什么是本地方法?简单地讲,一个Native Method就是一个Java调用非Java代码的接口。一个Native Method是这样一个Java方法:该方法的实现由非Java语言实现,比如C。这个特征并非Java所特有,很多其它的编程语言都有这一机制,比如在C++中,你可以用extern “C” 告知C++编译器去调用一个c的函数。“A native method is a Java method whose implementation is provided by non-java code.”原创 2021-11-24 18:07:25 · 171 阅读 · 0 评论 -
虚拟机栈的5道面试题
举例栈溢出的情况当栈大小固定时,不断增加栈帧数量直至栈所能容纳的最大值,就会发生StackOverflowError异常。当栈的大小可以动态扩展时,当栈扩展至内存不足时,会发生OutOfMemoryError异常。设置栈大小,就能保证不出现溢出吗?不能。例如:递归死循环时,不论设置栈多大,都会出现栈溢出的情况。分配的栈内存越大越好吗?不是,分配的栈内存越大会导致可创建的线程数量减少以及其他区域可用空间变小,进而影响程序的执行。垃圾回收是否涉及到虚拟机栈?不涉及,栈的出栈操作就相当于丢弃垃圾。原创 2021-11-23 15:59:31 · 468 阅读 · 0 评论 -
虚拟机栈(Java Stack)
概述由于跨平台性的设计,Java的指令都是根据栈来设计的。不同平台CPU架构不同,所以不能设计为基于寄存器的。优点是跨平台,指令集小,编译器容易实现,缺点是性能下降,实现同样的功能需要更多的指令。栈是运行时的单位,而堆是存储的单位。虚拟机栈关心的是程序如何运行以及数据如何处理,堆关心的是数据如何存放及放在什么位置。每个线程在创建时都会创建一个虚拟机栈,其内部保存一个个的栈帧(Stack Frame) ,对应着一次次的Java方法调用。是线程私有的。生命周期与线程一致主管Java程序的运行,它保原创 2021-11-22 12:04:41 · 355 阅读 · 0 评论 -
程序计数器(PC寄存器)
概述JVM中的PC寄存器是对物理寄存器的一种抽象模拟。作用:PC寄存器用来存储指向下一条指令的地址,也即将要执行的指令代码。由执行引擎读取下一条指令。在JVM规范中,每个线程都有自己的一个程序计数器,是线程私有的。程序计数器的生命周期与线程的生命周期保持一致。任何时间一个线程都只有一个方法在执行,也就是所谓的当前方法。程序计数器会存储当前线程正在执行的Java方法的JVM指令地址;或者,如果是在执行native方法,则是未指定值(undefined)。它是程序控制流的指示器,分支、循环、跳转、异原创 2021-11-22 09:44:12 · 250 阅读 · 0 评论 -
运行时数据区概述及线程
运行时数据区结构Java虚拟机定义了若千种程序运行期间会使用到的运行时数据区,其中有一些会随着虚拟机启动而创建,随着虚拟机退出而销毁。另外一些则是与线程一一对应的,这些与线程对应的数据区域会随着线程开始和结束而创建和销毁。线程独享:程序计数器、虚拟机栈、本地方法栈。线程共享:堆区、堆外内存(永久代或元空间、代码缓存)。每个JVM只有一个Runtime实例。即为运行时环境,相当于内存结构的中间的那个框框:运行时环境。线程线程是一个程序里的运行单元。JVM允许一个应用有多个线程并行的执行。原创 2021-11-22 08:53:38 · 779 阅读 · 0 评论 -
类加载子系统其他内容
一、在JVM中表示两个class对象是否为同一个类存在两个必要条件:类的完整类名必须一致,包括包名。加载这个类的ClassLoader必须相同。二、JVM必须知道一个类型是由启动类加载器加载的还是由用户类加载器加载的。如果一个类型是由用户类加载器加载的,那么JVM会将这个类加载器的一个引用作为类型信息的一 部分保存在方法区中。当解析一个类型到另一个类型的引用的时候,JVM需 要保证这两个类型的类加载器是相同的。三、Java程序对类的使用分为:主动使用和被动使用主动使用,又分为七种情况:(原创 2021-11-20 14:41:40 · 201 阅读 · 0 评论 -
双亲委派机制
什么是双亲委派机制?Java虛拟机对class文件采用的是按需加载的方式,也就是说当需要使用该类时才会将它的class文件加载到内存生成class对象。而且加载某个类的class文件时,Java虚拟机采用的是双亲委派模式,即把请求交由父类处理,它是一种任务委派模式。工作原理如果一个类加载器收到了类加载的请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行。如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将达到顶层的启动类加载器。如果父类加载器可以完成类加载任务原创 2021-11-20 10:59:38 · 71 阅读 · 0 评论 -
关于ClassLoader
关于ClassLoaderClassLoader类是一个抽象类,其后所有的类加载器都继承自ClassLoader(不包括启动类加载器)。常用方法方法名称描述getParent()返回该类加载器的超类加载器loaderClass(String name)加载名称为name的类,返回结果为java.lang.Class类的实例findClass(String name)查找名称为name的类,返回结果为java.lang.Class类的实例findLoadedC原创 2021-11-20 10:39:10 · 197 阅读 · 0 评论 -
用户自定义类加载器
用户自定义类加载器在Java的日常应用开发中,类的加载几乎由引导类加载器,扩展类加载器和系统类加载器相互配合执行的,在必要时可以自定义类加载器,来定制类的加载方式。为什么要自定义类加载器隔离类加载器修改类的加载方式扩展加载源防止源码泄露...原创 2021-11-20 10:17:09 · 113 阅读 · 0 评论 -
常见的三种类加载器
Bootstrap Class Loader引导类加载器这个类加载器使用C/C++语言实现的,嵌套在JVM内部。它用来加载JAVA的核心库(JAVAHOME/jre/lib/rt.jar、resources.jar或sum.boot.class.path路径下的内容),用于提供JVM自身需要的类。并不继承子java.lang.ClassLoader,没有父加载器。加载扩展类和应用程序类加载器,并指定为阀门的父类加载器。出于安全考虑,Bootstrap启动类加载器只加载包名为java、javax、原创 2021-11-20 09:09:13 · 1074 阅读 · 0 评论 -
类加载器与类的加载过程
类加载器子系统作用类加载器子系统负责从文件系统或者网络中加载Class文件,class文件在文件开头有特定的文件标识。ClassLoader只负责class文件的加载,至于它是否可以运行,则由执行引擎决定。加载的类信息存放于一块称为方法区的内存空间。除了类信息外,方法区中还会存放常量池信息,可能还包括字符串字面量和数字常量(这部分常量信息是Class文件中常量池部分的内存映射)。类加载器ClassLoader角色class file 存在与本地硬盘上,通过ClassLoader将class原创 2021-11-19 13:11:06 · 94 阅读 · 0 评论