
JVM
xinlingmen
这个作者很懒,什么都没留下…
展开
-
JVM学习笔记第51天-Java中几种不同的引用
一、概述我们希望能描述这样一类对象,当内存空间还足够时,则能保留在内存中,如果内存空间在进行垃圾收集后还是很紧张,则可以抛弃这些对象。强引用、软引用、弱引用、虚引用有什么区别?具体使用场景是什么?在JDK1.2之后,Java对引用概念进行了扩充,将引用分为强引用、软引用、弱引用、虚引用4种,这4种引用强度依次逐渐减弱。除强引用外,其它3种引用均可以在java.lang.ref包中找到他们的身影。如下图,显示了这3种引用类型对应的类,开发人员可以在应用程序种直接使用它们。二、四种引原创 2020-08-11 14:42:19 · 119 阅读 · 0 评论 -
JVM学习笔记第50天-StopTheWorld事件的理解
一、概述Stop-The-World ,简称STW,指的是GC事件发生过程中,会产生应用程序的停顿。停顿产生时整个应用程序线程都会被暂停,没有任何相应,有点像卡死的感觉,这个停顿称为STW。可达性分析算法中枚举根节点(GC Roots)会导致所有Java执行线程停顿。分析工作必须在一个能确保一致性的快照中进行。 一致性指整个分析期间整个执行系统看起来像被冻结在某个时间点上。 如果出现分析过程中对象引用关系还在不断变化,则分析结果的准确性无法保证。被STW中断的应用程序线程会在完成GC之后恢复原创 2020-08-07 17:02:48 · 260 阅读 · 0 评论 -
JVM学习笔记第49天-内存泄漏
一、概述也称作“存储泄漏”。严格来说,只有对象不会再被程序用到了,但是GC又不能回收它们的情况,才叫内存泄漏。实际情况,很多时候一些不太友好的实践(或疏忽)会导致对象的生命周期变得很长,甚至导致OOM,也可以叫做宽泛意义上的“内存泄漏”。尽管内存泄漏并不会立刻引起程序崩溃,但是,一旦发生内存泄漏,程序中的可用内存就会被逐步蚕食,直至耗尽所有内存,最终出现OutOfMemory异常,导致程序崩溃。注意:这里的存储空间并不是指物理内存,而是指虚拟内存大小,这个虚拟内存大小取决于磁盘区交换设定的大原创 2020-08-07 16:40:46 · 119 阅读 · 0 评论 -
JVM学习笔记第48天-内存溢出
一、概述内存溢出相对于内存泄漏来说,尽管更容易被理解,但是同样的,内存溢出也是引发程序崩溃的罪魁祸首之一。 由于GC一直在发展,所以一般情况下,除非应用程序占用的内存增长速度非常快,造成垃圾回收已经跟不上内存消耗的速度,否则不太容易出现OOM的情况; 大多数情况下,GC会进行各年龄段的垃圾回收,实在不行了就放大招,来一次独占式的Full GC操作,这时候会回收大量的内存,供应用程序继续使用。 javadoc中对OutOfMemoryError的解释是,没有空闲内存,并且垃圾收集器也无法提供更多内存原创 2020-08-05 15:17:41 · 146 阅读 · 0 评论 -
JVM学习笔记第47天-分区算法
一、分区算法一般来说,在相同条件下,堆空间越大,一次GC所需要的时间越长,有关GC产生的停顿越长。为了更好的控制GC产生的停顿时间,将一块大的内存区域分割成多个小块,根据目标的停顿时间,每次合理的回收若干个小区间,而不是整个堆空间,从而减少一次GC停顿的时间。分代算法将按照对象的生命周期长短划分成两个部分,分区算法将整个堆空间划分成连续的不同小区间。每一个小区间都独立使用,独立回收。这种算法的好处是可以控制一次回收多少个小区间。二、内存图示三、特别提示上述算法只是基本思路,实际G原创 2020-07-30 10:22:24 · 277 阅读 · 0 评论 -
JVM学习笔记第46天-增量收集算法
一、增量收集算法现有算法,在垃圾回收过程中,应用软件将处于一种Stop the World 的状态。在Stop the World 状态下,应用程序所有的线程都会挂起,暂停一切正常的工作,等待垃圾回收的完成。如果垃圾回收时间过长,应用程序会被挂起很久,将严重影响用户体验或者系统的稳定性。为了解决这个问题,即对实时垃圾收集算法的研究直接导致了增量收集(Incremental Collecting)算法的诞生。基本思想如果一次性将所有的垃圾进行处理,需要造成系统长时间的停顿,那么就可以让垃圾收集线程原创 2020-07-30 10:12:27 · 519 阅读 · 0 评论 -
JVM学习笔记第45天-分代收集算法说明
前面所有这些算法,没有一种算法可以代替其它算法,他们都有自己独特的优势和特点。分代收集算法应运而生。 分代收集算法,是基于这样一个事实:不同的对象的生命周期是不一样的。因此,不同生命周期的对象可以采用不同的收集方式,以便提高回收效率。一般是把Java堆分为新生代和老年代,这样就可以根据各个年代的特点使用不同的回收算法,以提高垃圾回收的效率。 在Java程序运行的过程中,会产生大量的对象,其中有些对象是与业务有关,比如:http请求中的Session对象、线程、Socket连接,这类对象跟业务直接挂钩,因原创 2020-07-29 17:55:21 · 148 阅读 · 0 评论 -
JVM学习笔记第44天-标记-压缩(整理)算法
一、标记-压缩算法背景复制算法的高效性是建立在存活对象少、垃圾对象多的前提下的。这种情况在新生代经常发生,但是在老年代,更常见的情况是大部分对象都是存活对象。如果依然使用复制算法,由于存活对象多,复制成本也将很高。因此,基于老年代垃圾回收的特性,需要使用其它的算法。标记-清除算法确实可以应用在老年代中,但是,该算法不仅执行效率低下,而且在执行完内存收集后,还会产生内存碎片,所以JVM的设计者需要在此基础上进行改进。标记-压缩(Mark Compact)算法由此诞生。1970年前后,G.L.S原创 2020-07-29 10:38:27 · 880 阅读 · 0 评论 -
JVM学习笔记第43天-复制算法及优缺点
一、复制算法背景为了解决标记-清除算法在垃圾收集效率方面的缺陷,M.L.Minsky于1963年发表了著名的论文,“使用双存储区的Lisp语言垃圾收集器CA Lisp Garbage Collector Algorithm Using Serial Secondary Storage”。M.L.Minsky在论文中描述的算法被人们称为复制(Copying)算法,它也被M.L.Minsky本人成功的引入到了Lisp语言的一个实现版本中。核心思想将活着的内存空间分为两块,每次只使用其中一块,在垃原创 2020-07-29 10:01:58 · 828 阅读 · 1 评论 -
JVM学习笔记第42天-标记清除算法原理及优缺点
一、标记清除算法背景标记-清除算法(Mark-Sweep)是一种非常基础和常见的垃圾收集算法,该算法被J.McCarthy等人在1960年提出并应用于Lisp语言。执行过程当堆中的有效内存空间(available memory)被耗尽的时候,就会停止整个程序(也被称为Stop The World),然后进行两项工作,第一项是标记,第二项则是清除。标记:Collector从引用根节点开始遍历,标记所有被引用的对象。一般是在对象的Header中记录为可达对象。 清除:Collector对堆原创 2020-07-29 09:43:46 · 790 阅读 · 0 评论 -
JVM学习笔记第41天-对象的finalization机制
原创 2020-07-24 14:29:34 · 170 阅读 · 0 评论 -
JVM学习笔记第40天-可达性分析算法
一、概述可达性分析算法,又叫根搜索算法或者追踪性垃圾收集。 相对于引用计数算法而言,可达性分析算法不仅同样具备实现简单和执行高效等特点,更重要的是该算法可以有效的解决在引用计数算法中循环引用的问题,防止内存泄露的发生。 相较于引用计数算法,这里的可达性分析就是Java、C#选择的。这种类型的垃圾收集通常也叫做追踪性垃圾收集(Trace Garbage Collection); 所谓“GC Roots"根集合就是一组必须活跃的引用。 基本思路可达性分析算法是以根对象集合(GC Roots)为起始原创 2020-07-24 11:59:36 · 427 阅读 · 0 评论 -
JVM学习笔记第39天-引用计数算法
一、原理引用计数算法(Rerference Counting)比较简单,对每个对象保存一个整型的引用计数器属性,用于记录对象被引用的情况。 对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器就加1;当引用失效时,引用计数器就减1;只要对象A的引用计数器为0,即表示对象A不可能再被使用,可进行回收。二、优缺点优点实现简单,垃圾对象便于辨识,判定效率高,回收没有延迟性。缺点它需要单独的字段存储计数器,这样的做法增加了存储空间的开销。 每次赋值都需要更新引用计数器,伴随着加法和原创 2020-07-24 10:50:10 · 224 阅读 · 0 评论 -
JVM学习笔记第38天-垃圾标记阶段
在Java堆里存放着几乎所有的Java对象实例,在GC执行垃圾回收之前,首先需要区分出内存中哪些是存活对象,哪些是已经死亡的对象。只有标记为已经死亡的对象,GC才会在执行垃圾回收时,释放掉其所占用的内存空间,因此这个过程我们可以称为垃圾标记阶段。 那么在JVM中,如何标记一个死亡对象呢?简单来说,当一个对象已经不再被任何存活的对象继续引用时,就可以宣判为已经死亡。 判断对象存活一般有两种方式:引用计数算法和可达性分析算法。...原创 2020-07-24 10:35:42 · 135 阅读 · 0 评论 -
JVM学习笔记第37天-String.intern()相关的面试题
题目1new String("ab")会创建几个对象?代码字节码结论会创建2个对象,一个是new String("ab")对象,一个是ldc放到字符串常量池中的对象;题目二思考:new String("a")+new String("b") 创建了几个对象;代码字节码结论题目三代码结论内存图解...原创 2020-07-23 15:35:26 · 131 阅读 · 0 评论 -
JVM学习笔记第36天-字符串拼接操作的底层原理
例子1代码字节码结论例子2代码字节码结论原创 2020-07-23 11:21:45 · 94 阅读 · 0 评论 -
JVM学习笔记第35天-字符串拼接操作
一、概述常量与常量的拼接结果在常量池,原理是编译期优化; 常量池中不会存在相同内容的常量。 只要其中有一个是变量,结果就在堆中。变量拼接的原理是StringBuilder。 如果拼接的结果调用intern()方法,则主动将常量池中还没有的字符串对象放入池中,并返回此对象地址。二、举例例子1class文件的反编译结果如下:证明常量与常量的拼接,在编译期就优化了;"a"+"b"+"c" 相当于 "abc";例子2证明,如果拼接过程有变量,则拼接结果是放在堆中,而不是常原创 2020-07-23 10:52:09 · 114 阅读 · 0 评论 -
JVM学习笔记第34天-机器码 、指令、汇编、高级语言理解与执行过程
一、机器码各种用二进制编码方式表示的指令,叫做机器指令码;刚开始,人们就用它编写程序,这就是机器语言。 机器语言虽然能够被计算机理解和接受,但是和人们的语言差别太大,不易被人们理解和记忆,并且用它编程容易出差错。 用它编写的程序一经输入计算机,CPU直接读取运行,因此和其它语言编的程序相比,执行速度最快。 机器指令与CPU紧密相关,所以不同种类的CPU所对应的机器指令也就不同。二、指令指令由于机器码是由0和1组成的二进制序列,可读性实在太差,于是,人们发明了指令。 指令就是把机器码..原创 2020-07-22 15:01:55 · 634 阅读 · 0 评论 -
JVM学习笔记第33天-解释器和JIT编译器
解释器:当JAVA虚拟机启动时,会根据预定义的规范对字节码采用逐行解释的方式执行,将每条字节码文件中的内容“翻译”为对应平台的本地机器指令执行。 JIT(Just in time Compiler)编译器:就是虚拟机将源代码直接编译成和本地机器平台相关的机器语言。为什么说Java是半编译半解释性语言?JDK1.0时代,将Java语言定位为“解释执行”,还是比较准确的。再后来,Java也发展出可以直接生成本地代码的编译器。现在JVM在执行Java代码的时候,通常都会将解释执行与编译执行两者结合起原创 2020-07-22 14:14:13 · 173 阅读 · 0 评论 -
JVM学习笔记第32天-执行引擎执行过程
原创 2020-07-22 11:54:03 · 130 阅读 · 0 评论 -
JVM学习笔记第31天-对象访问定位
一、概览1.1图示1.2句柄访问1.3直接指针原创 2020-07-22 11:46:09 · 83 阅读 · 0 评论 -
JVM学习笔记第30天-对象内存布局
一、思维导图二、图示代码代码对应的内存示意图原创 2020-07-22 11:18:12 · 91 阅读 · 0 评论 -
JVM学习笔记第29天-对象的实例化
原创 2020-07-22 09:59:05 · 111 阅读 · 0 评论 -
JVM学习笔记第28天-StringTable(字符串常量池)为什么要调整到堆中?
jdk7中将StringTable放到了堆空间中。因为永久代的回收效率很低,在full GC的时候才会触发。而Full GC是老年代空间不足、永久代空间不足时才会触发。这就导致StringTable回收效率不高。而我们开发中会有大量的字符串被创建,回收效率低,导致永久代内存不足。放到堆里,能及时回收内存。...原创 2020-07-21 16:44:28 · 1226 阅读 · 3 评论 -
JVM学习笔记第27天-方法区的演进细节
一、概述首先明确,只有HotSpot才有永久代;BEA JRockit、IBM J9等来说,是不存在永久代的概念的。原则上如何实现方法区属于虚拟机实现细节,不受《JAVA虚拟机规范》约束,并不要求统一。HotSpot中方法区的变化二、永久代为什么要被元空间替代?为永久代设置空间大小是很难确定的。在某些场景下,如果动态加载类过多,容易产生Perm区的OOM。比如某个实际web工程中,因为功能点比较多,在运行过程中,要不断动态加载很多类,经常出现致命错误。 而元空间和永久代之间最大原创 2020-07-21 16:33:59 · 202 阅读 · 0 评论 -
JVM学习笔记第26天-方法区使用示意图
一、类信息二、方法区使用示意图原创 2020-07-21 14:55:05 · 98 阅读 · 0 评论 -
JVM学习笔记第25天-运行时常量池和常量池
一、概述方法区,内部包含了运行时常量池; 字节码文件,内部包含了常量池; 要弄清楚方法区,需要理解清楚ClassFile,因为加载类的信息都在方法区; 要弄清楚方法区的运行时常量池,需要理解清楚Class File文件中的常量池;一个有效的字节码文件中除了包含类的版本信息、字段、方法以及接口等描述信息外,还包含一项信息,那就是常量池表(Constant Pool Table),包括各种字面量和对类型、域和方法的符号引用。二、为什么需要常量池?三、运行时常量池运行时常量原创 2020-07-21 14:11:59 · 190 阅读 · 0 评论 -
JVM学习笔记第24天-方法区内部结构
一、概览图二、方法区存储什么?《深入理解JAVA虚拟机》书中对方法区(Method Area)存储内容描述如下:它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等。类型信息对每个加载的类型(类class、接口interface、枚举enum、注解annotation),JVM必须在方法区中存储以下类型信息:这个类型的有效完整名称(全名=包名.类名) 这个类型直接父类的有效完整名称(对于interface或java.lang.object,都没有父类)原创 2020-07-21 11:18:51 · 172 阅读 · 0 评论 -
JVM学习笔记第23天-设置方法区大小的参数
方法区的大小不必是固定的,JVM可以根据应用的需要动态调整;JDK7及以前:通过-XX:PermSize来设置永久代初始分配空间。默认值是20.75M。 -XX:MaxPermSize来设定永久代最大可分配空间。32位机器默认是64M,64位机器默认是84M; 当JVM加载类信息超过这个值,会报异常OutOfMemoryError:PermGen space;JDK8及以后:元数据区大小可以使用参数:-XX:MetaspaceSize和-XX:MaxMetaspaceSize; 默认值依原创 2020-07-21 10:34:54 · 848 阅读 · 0 评论 -
JVM学习笔记第22天-栈、堆、方法区之间的关系
示意图创建一个对象,分别用到了栈、堆、方法区;如例子,Person的对象类型信息在方法区,person变量在栈中,new Person()对象实例数据在堆中。原创 2020-07-18 11:58:39 · 94 阅读 · 0 评论 -
JVM学习笔记第21天-Minor GC、Major GC和Full GC的区别
一、概述JVM在进行GC时,并非每次都对新生代、老年代、方法区三大内存区域一块回收,大部分时候的回收指的是新生代。针对HotSpot VM的实现,它里面的GC按照回收区域分为两大类型:一种是部分收集(Partial GC);一种是整体收集(Full GC);部分收集:不是完整收集整个Java堆的垃圾收集;新生代收集(Minor GC / Young GC):只是新生代的垃圾收集; 老年代收集(Major GC / Old GC):只是老年代的垃圾收集;目前只有CMS GC,会有单独收集老..原创 2020-07-16 12:36:23 · 358 阅读 · 0 评论 -
JVM学习笔记第20天-对象分配的流程图
原创 2020-07-16 11:00:00 · 154 阅读 · 0 评论 -
JVM学习笔记第19天-JVM中对象分配的过程
为对象分配内存是一件非常严谨和复杂的任务,JVM的设计者不仅需要考虑内存如何分配,在哪里分配等问题,并且由于内存分配算法与内存回收算法密切相关,所以还需要考虑GC执行完内存回收后,是否会在内存空间中产生内存碎片。new的对象先放伊甸园区,此区有大小限制。 当伊甸园的空间填满时,程序又需要创建对象,JVM的垃圾回收器将对伊甸园区进行垃圾回收(Minor GC),将伊甸园区中的不再被其它对象所引用的对象销毁。再加载新的对象放到伊甸园区。 然后将伊甸园中剩余的对象移动到幸存者0区。 如果再次触发垃圾回收原创 2020-07-15 17:16:33 · 223 阅读 · 0 评论 -
JVM学习笔记第18天-堆空间
1、堆空间大小的设置Java堆区用于存储Java对象实例,那么堆的大小在JVM启动时就已经设定好了,大家可以通过选项“-Xmx"和”-Xms“来进行设置。”-Xms"用于表示堆区的起始内存,等价于-XX:InitialHeapSize; “-Xmx"用于表示堆区的最大内存,等价于-XX:MaxHeapSize;一旦堆区中的内存大小超过”-Xmx"所指定的最大内存时,将会抛出OutOfMemoryError异常; 通常会将 -Xms 和 -Xmx两个参数配置相同的值,其目的是为了能够在Java垃圾原创 2020-07-15 16:59:08 · 147 阅读 · 0 评论 -
JVM学习笔记第17天-方法返回地址(return address)
1、基本介绍用来存放调用该方法的PC寄存器的值。 一个方法的结束有两种方式:正常执行完成; 出现未处理的异常,非正常退出。无论通过哪种方式退出,在方法退出后都返回到该方法被调用的位置。方法正常退出时,调用者的PC寄存器的值作为返回地址,即调用该方法的指令的下一条指令的地址。而通过异常退出的,返回地址是要通过异常表来确定,栈帧中一般不会保存这部分信息。2、退出方法的两种方式当一个方法开始执行后,只有两种方式可以退出这个方法:1、执行引擎遇到任意一个方法返回的字节码指令(return),会原创 2020-07-13 16:16:32 · 1250 阅读 · 1 评论 -
JVM学习笔记第16天-虚方法表
在面向对象的编程中,会频繁的使用动态分派,如果在每次的动态分派的过程中都要重新在类的方法元数据中搜索合适的目标的话,可能影响到执行效率。因此,为了提高性能,JVM采用在类的方法区建立一个虚方法表(virtual method table)(非虚方法不会出现在表中)来实现。使用索引表来代替查找。 每个类中都有一个虚方法表,表中存着各个方法的实际入口。 虚方法表什么时候创建? 虚方法表会在类加载的链接阶段被创建并开始初始化,类的变量初始值准备完成之后,JVM会把该类的方法表也初始化完毕。...原创 2020-07-13 15:39:00 · 1386 阅读 · 0 评论 -
虚方法与非虚方法
非虚方法:如果方法在编译期就确定了具体的调用版本,这个版本在运行时是不可变的,这样的方法称为非虚方法;静态方法、私有方法、final方法、实例构造器、父类方法都是非虚方法;虚方法:不是非虚方法的方法,都是虚方法;调用指令:虚拟机中提供了以下几条方法调用指令:普通调用指令:1、invokestatic:调用静态方法,解析阶段确定唯一方法版本;2、invokespecial:调用<init>方法、私有及父类方法,解析阶段确定唯一方法版本;3、invokevir原创 2020-07-13 11:15:33 · 1032 阅读 · 0 评论 -
方法的绑定机制:静态绑定与动态绑定
在jvm中,将符号引用转换为方法的直接引用与方法的绑定机制相关;静态链接当一个字节码文件被装载进JVM内部时,如果被调用的方法在编译期可知,且运行期保持不变时。这种情况下将调用方法的符号引用转换为直接引用的过程称之为静态链接;动态链接如果被调用的方法在编译期无法被确定下来,也就是说,只能够在程序运行期将调用方法的符号引用转换为直接引用,由于这种引用过程具备动态性,因此也被称之为动态链接;对应的方法的绑定机制为:早期绑定(Early Binding)和晚期绑定(Late Binding).原创 2020-07-09 11:27:14 · 223 阅读 · 0 评论 -
JVM学习笔记第15天-操作数栈
特点每一个独立的栈帧中除了包含局部变量表以外,还包含一个后进先出(Last-In-First-Out)的操作数栈,也可以称之为表达式栈(Expression Stack)。 操作数栈,在方法执行过程中,根据字节码指令,往栈中写入数据或者提取数据,即入栈(push)/出栈(pop)。某些字节码指令将值压入操作数栈,其余的字节码指令将操作数取出栈,使用它们后,再把结果压入栈。 比如:执行复制、交换、求和操作。操作数栈,主要用于保存计算过程的中间结果,同时作为计算过程中变量临时的存储空间。 操作原创 2020-06-09 17:20:35 · 171 阅读 · 0 评论 -
JVM学习笔记第14天-局部变量表
基本介绍局部变量表也被称为局部变量数组或本地变量表; 定义为一个数字数组,主要用于存储方法参数和定义在方法体内的局部变量,这些数据类型包括各类基本数据类型、对象引用(reference)、以及returnAddress类型; 由于局部变量表是建立在线程的栈上,是线程的私有数据,因此不存在数据安全问题; 局部变量表所需的容量大小是在编译期确定下来的,并保存在方法的Code属性的Maximum local variables数据项中,在方法运行期间是不会改变局部变量表的大小; 方法嵌套调用的次数由栈原创 2020-06-08 14:58:05 · 151 阅读 · 0 评论