jvm
文章平均质量分 53
隐0士
这个作者很懒,什么都没留下…
展开
-
jvm之内存泄露
概述可达性分析算法来判断对象是否是不再使用的对象,本质都是判断一个对象是否还被引用。那么对于这种情况下,由于代码的实现不同就会出现很多种内存泄漏问题(让™误以为此对象还在引用中,无法回收,造成内存泄漏)。内存泄漏(memory leak)的理解严格来说,只有对象不会再被程序用到了,但是GC又不能回收他们的情况,才叫内存泄漏。但实际情况很多时候一些不太好的实践(或疏忽)会导致对象的生命周期变得很长甚至导致OOM,也可以叫做宽泛意义上的“内存泄漏”。对象X引用对象Y,X的生命周期比Y的生命周期长;那么原创 2021-11-21 21:12:21 · 408 阅读 · 0 评论 -
MAT(Memory Analyzer Tool)工具使用超详细版
概述MAT(Memory Analyzer Tool)工具是一款功能强大的]ava堆内存分析器。可以用于查找内存泄漏以及查看内存消耗情况。MAT是基于Eclipse开发的,不仅可以单独使用,还可以作为插件的形式嵌入在Eclipse中使用。是一款免费的性能分析工具,使用起来非常方便。大家可以在https://www.eclipse.org/mat/downloads.php下载并使用MAT。 !MAT可以分析heap dump文件。在进行内存分析时,只要获得了反映当前设备内存映像的hprof文件,通过M原创 2021-11-21 16:02:23 · 41580 阅读 · 4 评论 -
jvm对象创建与实例化
创建对象的方式有以下六种:直接new、调用Xx的静态方法、使用XxxBuilder/XFactory的静态方法Class的newinstance0 :反射的方式,只能调用空参的构造器,权限必须是public(已经被废弃)Constructor的newinstance(Xxx):反射的方式,可以调用空参、带参的构造器,权限没有要求使用cloneo:不调用任何构造器,当前类需要实现Cloneable接口,实现clone0使用反序列化:从文件中、从网络中获取一个对象的二进制流第三方库Objenes原创 2021-11-08 17:17:49 · 83 阅读 · 0 评论 -
jvm方法区的垃圾回收
一般来说方法区的回收很难令人满意,因为条件苛刻所以回收效果不太好,但又是需要的。方法区主要回收的是两个东西:类型信息和运行时常量池。运行时常量池字面量和符号引用,字面量主要包括三类:类和接口的全限定名字段的名称和描述符方法的名称和描述符只要常量池的常量没有被引用,就可以回收。类型信息判断一个类型不再被使用的条件比较苛刻,需要满足以下三个条件:该类的所有实例都被回收了加载该类的类加载器已经被回收,除非是经过精心设计的可替换类加载器的场景,如OSGi、JSP的重加载等,否则是很难达成的原创 2021-11-08 16:52:32 · 220 阅读 · 0 评论 -
jvm方法区的演进细节
只有hotspot才有永久代,,在hotspot中方法区的变化如下:jdk6时有永久代,静态变量放在永久代中jdk7时,有永久代,但逐渐被放弃,字符串常量池、静态变量从永久代移除,保存到堆中。jdk8及以后,就没有永久代了,类型信息,字段,方法,常量保存在本地内存中的元空间里,但字符串常量以及静态变量仍然放在堆中。永久代为什么会被元空间替代?1、官网的说法是JRockit没有永久代,在hotspot合并后,就不提供这样的参数配置了。2、为永久代设置空间大小是很难确定的,如果在某些场景下动态原创 2021-11-08 16:49:38 · 115 阅读 · 0 评论 -
jvm运行时常量池和常量池
概述常量池是字节码信息中的一部分,在类的字节码文件中我们能看到常量池信息常量信息:那么这个常量池跟方法区的运行时常量池有什么关系呢,这里的常量池加载进内存就叫运行时常量池,常量池包括了各种字面量和对类型、域、方法的符号引用,具体为数量值,字符串值,类引用,字段引用,方法引用。为什么需要常量池一个java源文件编译会形成一个字节码文件,但是字节码文件里其实是需要其他数据支持的,如果将其他数据也一并放入此字节码文件中,则会使得字节码文件变得贼大。那么如果放的是引用呢,那么就会极大地缩小字节码的大小。原创 2021-11-04 21:10:53 · 195 阅读 · 0 评论 -
jvm方法区的内部结构
概述方法区内存存储的是类型信息、field域信息,方法信息 ,常量,静态变量,运行时常量池,即时编译器编译后的代码缓存。类型信息:对于类、接口、枚举、注解都要存储一下信息:1、类型的完整有效名称,比如说包名2、类型的直接父类的完整有效名称3、类型的修饰符4、类型的直接接口的一个有序的列表(因为接口可以多实现)域信息域名称、域信息、域修饰符(public,private,protected,static ,final volatile ,transient)方法信息方法名称、方法返回类型原创 2021-11-04 21:09:01 · 152 阅读 · 0 评论 -
jvm设置方法区大小的参数
jdk7及以前:通过-XX:PermSize 来设置永久代初始分配空间,默认值是20.75m-XX:MaxPermSize来设定永久代最大可分配空间,32位是64m,64位是82mjdk8及之后:通过-XX:MetaspaceSize 来设置永久代初始分配空间,默认值是21m-XX:MaxMetaspaceSize来设定永久代最大可分配空间,值为-1由于没有上限,因此当本机内存耗尽时,会抛出oom的错误,对于起始值21m来说,如果所使用的内存超过这个值,则会触发full gc卸载没用的类,之后将原创 2021-11-04 20:59:50 · 885 阅读 · 0 评论 -
jvm方法区的基本理解
概述方法区在逻辑上是堆的一部分,但因为一些简单的实现不会选择去进行垃圾收集或者压缩,所以可以把方法区看做是一块独立于java堆的内存空间方法区跟堆一样,是各个线程共享的区域方法区在启动的时候就创建了,实际内存可以是不连续的方法区的大小是可以扩展的或配置固定大小,大小决定了系统可以保存多少个类,如果加载的类过多则会报oom异常,如加载了大量的第三方jar包,tomcat部署的工程很多,有大量动态生成的反射类。关闭jvm就会释放方法区的内存方法区的演进jdk7之前是永久代,jdk8开始就使用元原创 2021-11-02 23:49:47 · 131 阅读 · 0 评论 -
jvm内存结构中方法区,堆、栈的关系
元空间是方法区的落地实现,永久代是方法区旧版的落地实现。从线程是否共享的角度来看从一段代码的调用实例看Person person=new Person();Person类信息是在方法区中,实例化出来的对象是放在堆中,对象的引用变量是在虚拟机栈的局部变量表中从程序执行来看在局部变量表中的引用是堆里的对象引用,而堆里的对象保留着对象类型的引用...原创 2021-11-02 23:46:00 · 82 阅读 · 0 评论 -
minor GC、Major GC、Full GC区别
hotspot vm的gc分为部分收集和整堆收集。部分收集新生代收集:minorGC又称YoungGC,只是对Eden和S0,S1回收,只有Eden满的时候才会引发GC,GC就会引发STW(stop the world),虽然GC很频繁,但是回收速度很快,因此总的来说不会太影响用户线程。老年代收集:Major GC/Old GC,只有CMS GC会有单独收集老年代的行为,这里需要注意的是很容易和full GC混淆,主要区分就是是不是专门回收老年代混合收集:Mixed GC,收集整个新生代以及部分老原创 2021-10-31 15:38:49 · 324 阅读 · 0 评论 -
线程本地分配缓存TLAB
概念为了避免一系列的非线程安全问题,同时还能提升内存分配的吞吐量,它是在eden空间进行分配的,每个线程都有一个缓冲区域,空间只有Eden的1%,可以通过-XX:UseTLAB来配置是否开启tlab(默认是开启的),通过-XX:TLABWasteTargetPercent来设置TLAB空间所占用Eden空间的百分比大小。为什么需要tlab在jvm中堆区是共享的区域,一旦在并发环境下从堆中划分内存空间,就可能会遇到分配到同一个内存地址的问题,为了避免多个线程操作同一个地址,就需要使用加锁等机制,但这会影原创 2021-10-31 15:31:36 · 373 阅读 · 0 评论 -
堆内存分配策略
1,对象优先进新生代2,大对象(等于或超过了伊甸园和幸存者区大小)直接放进老年代3,长时间存活的对象(默认gc超过15次还存活的对象,可以通过-XX: MaxTenuringThreshold设置)分配到老年代4,动态对象年龄判断:如果幸存者区中的相同年龄的所有对象大小大于幸存者区的一半,也大于或等于此年龄大小的对象可以直接进入老年代,不需要经过MaxTenuringThreshold的判断。...原创 2021-10-31 15:28:14 · 123 阅读 · 0 评论 -
堆空间的常用参数
-XX:printFlagsInitial:查看所有的参数默认初始值-XX:printFlagsFinal:查看所有参数的最终值(可能会存在修改的值,这里打印的是最终值)-xms:堆空间的初始值大小,默认为内存的1/64-xmx:对空间的最大大小,为内存的1/4-xmn:设置新生代的大小-XX:NewRatio:设置新生代和老年代的占比,默认为1:2,也就是值为2-XX:SurvivorRatio:设置新生代Eden和s0/s1的占比,默认为是8:1:1,也就是值为8-XX:MaxTenuri原创 2021-10-31 15:26:40 · 203 阅读 · 0 评论 -
堆是分配对象的唯一选择之逃逸分析
逃逸分析概念随着jtl编译器的发展,与逃逸分析技术的逐渐成熟,栈上分配,标量替换优化技术将会导致对象分配到堆上的这个结论变得不是那么地绝对了,如果经过逃逸分析后,一个对象并没有逃逸出方法,那么就有可能被优化成站上分配,而判断一个对象是否逃逸则是通过判断该对象是否有可能在方法外使用。逃逸分析是一种 有效减少java程序中同步负载和内存堆分配压力的跨函数全局数据流分析算法。逃逸分析开关默认是开启的,但可以通过参数-XX:+DoEscapeAnalysis进行开启关闭逃逸分析场景分析package c原创 2021-10-31 15:20:29 · 99 阅读 · 0 评论 -
jvm堆中对象分配过程
对象分配的顺序伊甸园->幸存者s0->幸存者s1->幸存者s0->幸存者s1(反复多次后)->老年代需要注意的点:生存区0不会主动产生minor gc,而是在伊甸园满时产生gc,gc的目标是伊甸园和幸存者区。针对幸存者s0和s1区的总结是:两者复制之后有交换,谁空谁就会变成to(有没有可能都不为空)幸存者区的对象15次之后就会晋升到老年代,这个次数也可以通过参数配置老年代的对象只有在内存不足时,才会触发 majorgc进行清理关于垃圾回收:会频繁在新生区收集,很原创 2021-10-30 18:00:29 · 152 阅读 · 0 评论 -
堆中的新生代和老年代
概述在堆存放的对象中,主要分为两大类:生命周期较短的瞬时对象,创建和消亡都非常迅速生命周期非常长,甚至有和jvm保持一致的周期在以上两种类型中,第一类对象占用的比例非常大,在jvm进行垃圾回收的时候,可以多关注第一类对象的回收,而第二类对象的回收可不必每次都关注,生命周期长的对象gc频率可以降低,为了效率考虑,jvm划分了新生代(又分为eden和survivor0空间和survivor1空间)和老年代两种内存区域,如下图所示:一般来说几乎所有的java对象都是在新生代的eden区被创建的,然原创 2021-10-30 17:55:13 · 176 阅读 · 0 评论 -
jvm中堆的概述
定义一个进程对应一个jvm实例,一个jvm实例有一个运行时数据区,运行时数据库拥有一个堆,方法区,多个线程拥有多个虚拟机栈,程序计数器,本地方法栈在jvm启动的时候被创建,其空间大小也确定了,是jvm管理的最大一块内存空间堆内存大小是可以调节的可以在物理上不连续,但在逻辑上要是连续的所有的线程都共享堆,但还可划分线程私有的缓冲区TLAB几乎所有的对象和数组都会分配到推上数组和对象可能永远不会存储在栈上,在栈保存着引用,指向堆的内存位置。在方法结束后,堆中的对象不会马上被移除,只有在垃圾回收原创 2021-10-17 21:39:50 · 165 阅读 · 0 评论 -
JDK自带的jvisualvm无法连接Java VisualVM插件中心
最近在学jvm相关的知识,需要用到visual gc的插件来看堆内存,但是打开jvisualvm后发现在线插件挂了,就如下图所示:于是需要修改设置中的url在修改url之前,先到https://visualvm.github.io/pluginscenters.html这个网址上找到与你jdk版本相对应的url,哦,记得翻墙改完发现可以连上了:想装啥插件就装吧,我就装了个Visual GC...原创 2021-10-17 20:55:49 · 366 阅读 · 0 评论 -
jvm本地方法栈
定义java虚拟机栈用于管理java应用的方法,而本地方法栈用于管理本地方法的调用。本地方法栈与虚拟机栈类似也是线程私有的,并且本身可以设置成固定大小也可扩展调用机制当某个线程调用一个方法时,将该方法压入虚拟机栈中,尔后此方法再调用本地方法时,会将本地方法通过动态链接的方式调用到实际的非java语言的方法。当执行本地方法时,由于可以直接跟操作系统打交道,便可以做到与jvm同样的权限,甚至可以做到如下事项:通过本地方法接口访问虚拟机的内部的运行时数据区可以使用本地处理器的寄存器直接从本地内存的堆原创 2021-10-17 19:56:05 · 125 阅读 · 0 评论 -
jvm本地方法接口
什么是本地方法native method就是一个java接口调用非java代码的接口, 一个native方法是由非java语言实现,在定义native时,可以不用实现体,因为具体实现是在外部实现的。native可以与其他java标识符连用,但abstract除外package com.lydon.test;public class IHaveNatives {public native void Native1();private native void Native2();nati原创 2021-10-17 19:54:28 · 90 阅读 · 0 评论 -
jvm虚拟机栈-方法返回地址
定义方法返回地址为存放该方法在寄存器中的值,也即是该方法的指令地址,方便执行引擎在执行完该方法后,回到该方法对应的指令行号,这样才能继续执行下去(因为当前方法执行完后,pc寄存器已经没有该方法的指令地址了)。方法退出的方式主要有两种,分为正常退出和异常退出,下面来详细讲述:执行引擎遇到任意一个方法返回的字节码指令(return),会有返回值传递给上层的方法调用者,简称正常完成出口。一个方法在正常调用完成之后究竟需要使用哪一个返回指令还需要根据方法返回值的实际数据类型而定。在字节码指令中,返回指令原创 2021-10-17 17:09:15 · 351 阅读 · 0 评论 -
jvm虚拟机栈-方法的调用
在jvm中的方法分为虚方法和非虚方法非虚方法如果方法在编译期间就确定了具体的调用版本,这个版本在运行时是不可变得,这样的方法称为非虚方法,具体有静态方法(不能被重写),私有方法(不能被重写),final方法(不能被重写),实例构造器(不能被重写),父类方法(明确地使用super的方法调用父类方法)都是非虚方法。虚方法除了非虚方法外的都是虚方法(除了final修饰的之外)虚与非虚方法对应的普通字节码指令非虚方法对应的字节码指令:invokestatic字节码指令:调用静态方法,解析阶段确定唯一方原创 2021-10-17 17:06:54 · 115 阅读 · 1 评论 -
jvm虚拟机栈-动态链接
动态链接、方法返回地址、一些附加信息在有些书中会称为侦数据区基本介绍动态链接又称为指向运行时常量池方法的引用,每个栈侦内部都会包含一个指向运行时常量池中该栈侦所属方法的引用,即是知道我是谁。在java源码被编译成字节码文件时,所有的变量和方法引用都作为符号引用保存在class文件的常量池(常量池在方法区中)里,比如 描述一个方法调用了另外的其他方法时,就是通过常量池中指向其他方法的符号引用来表示的,动态链接的作用就是为了将这些符号转为调用方法的实际直接引用。之所以用常量池,一是能共享常量,不必每份都原创 2021-10-17 16:58:05 · 410 阅读 · 0 评论 -
jvm虚拟机栈-栈顶缓存技术
基本介绍基于栈式的架构的虚拟机所使用的零地址指令更加紧凑,单完成一项操作的时候必然需要使用更多的入栈和出栈指令,虚拟机栈也是存在于内存中,这就意味着将需要更多的指令分派次数和内存读/写次数,频繁的执行内存读/写操作必然会影响执行速度,为了解决这一问题HotSpot JVM的设计者们提出了栈顶缓存(Top-of-Stack-Caching)技术,将栈顶元素(或栈顶周边)元素缓存到物理CUP的寄存器中,以此降低对内存的读写次数,提升执行引擎的执行效率。这个知识点暂时还不知道如何实现缓存栈顶数据的,要缓存多少原创 2021-10-17 16:52:45 · 173 阅读 · 0 评论 -
简单分析字节码指令执行中pc程序计数器,局部变量表,操作数栈的变化情况
首先假设我们有如下的代码:经编译后得到的字节码如下,前面的数字是指令地址:0 bipush 152 istore_13 bipush 85 istore_26 iload_17 iload_28 iadd9 istore_310 return现在从最开头的指令开始,一步一步分析pc程序计数器,局部变量表,操作数栈的变化情况:0 bipush 15 :将15压入操作数栈pc寄存器:0局部变量表:序号0:this引用操作数栈:152 istore_1:将操作数栈的15出栈原创 2021-10-17 10:22:07 · 348 阅读 · 0 评论 -
jvm栈侦中的操作数栈
定义主要用于保存计算过程的中间结果,同时作为计算过程中变量临时的存储空间是jvm执行引擎的一个工作区,当一个方法开始执行时,新的栈侦也随之创建,此时该方法操作数栈为空。每一个操作数栈都有明确的栈深度用于存储数值,在编译期间已确定,保存在方法的code属性中,为max_stack栈的任何一个元素都可以是任意的java数据类型,与局部变量表一样,32位占一个栈单位深度。64则占两个。操作数栈虽然是使用数组来实现,但仍然是栈结构,只能使用出栈入栈来完成操作,不能用索引下标访问。如果被调用的方法有原创 2021-10-17 10:14:02 · 110 阅读 · 0 评论 -
栈侦中的局部变量表
存储方式为一个数字数组,用于存储方法参数,定义在方法内部的局部变量以及返回的结果变量。数据类型包括八大基础数据类型,对象引用,以及returnAddress类型线程安全因为局部变量是在栈侦里,而栈侦又在虚拟机栈里,因此是线程私有的,是线程安全的容量确定在jvm编译时就确定了局部变量表的长度,保存code的maximum local variables数据项中,在运行时不会改变,例如通过jclasslib查看可知main方法的局部变量的长度为3,分别为args,test,num这三个生命周期原创 2021-10-16 11:49:56 · 119 阅读 · 0 评论 -
jvm 虚拟机栈中的栈侦
在栈中存储了什么?每个线程都会有自己的虚拟机栈,在栈中都是以栈侦 stack Frame的形式存在的,在这个线程上执行的每个方法都各自对应一个栈侦栈侦是一个内存区块,是一个数据集,维系着方法执行过程中的各种数据信息在一条活动的线程中,一个时间点上,只会有一个活动的栈侦,也就是在栈顶的栈侦是有效的,称之为当前栈侦,与其对应的方法即是当前方法,与其对应的类即为当前类。不同线程锁包含的栈侦是不允许相互引用的,即不可能在一个栈侦之中引用另外一个线程的栈侦。如果某层栈侦抛出异常,若上层没有处理,则将会直接原创 2021-10-16 11:44:15 · 51 阅读 · 0 评论 -
java虚拟机中的虚拟机栈
虚拟机栈是每个线程创建时都会创建的一个栈,内部保存一个个的栈侦,对应一次次的java方法调用,因为跟线程有关,所以是线程私有的,生命周期也跟线程博保持一致,作用是主管程序的运行,同时也保存着方法的局部变量(8种基本数据类型,对应的引用地址),中间结果,并参与方法的调用和返回。栈和堆的区别栈好比做菜时的操作,而堆则是放做菜材料的锅,一个是运行单位(当然运行单位还会有些辅助信息的存储,例如的是栈侦里面的局部变量表),一个是存储单位。栈的优点栈是一种快速有效的分配存储方式,访问速度仅次于程序计数器,jv原创 2021-10-16 11:40:37 · 162 阅读 · 0 评论 -
jvm双亲委派模式
双亲委派的机制在java虚拟机中,对class文件采取的加载方式是按需加载,当需要使用时才会将其class文件加载到内存中生成class对象,当加载时,采用的加载方式是双亲委派模式,即是说将请求由父类加载器处理,是一种任务委派的模式。工作原理当一个类加载器收到要加载类的请求,这时它不会马上去加载,而是将其委派给了他的父加载器去执行加载父加载器如果还存在父加载器,则进一步向上委托,直到最顶层的启动类加载器为止如果父类加载器能完成下面给上来的加载任务,则返回成功标志,若不能,则回退到子加载器进行加载原创 2021-10-10 23:21:40 · 66 阅读 · 0 评论 -
jvm类加载器的分类
jvm支持两种类型的类加载器,分别为:引导类加载器引导类加载器又叫启动类加载器,Bootstrap ClassLoader,有如下的特点:使用c/c++实现,嵌套在jvm内部用来加载java的核心库,如jre/lib/rt.jar,resources.jar,或sun.boot.class.path路径下的内容不继承java.lang.ClassLoader类,因为不是java语言实现的,也没有父类加载类处于安全考虑,只加载包名为java,javax,sun等开头的类自定义类加载器所有派原创 2021-10-10 23:09:02 · 249 阅读 · 0 评论 -
JVM虚拟机的发展历程
sun class vm是java1.0版本发布的第一款商用java虚拟机,其特点是只有解释器,如果需要编译器则需要外挂,但不能同时工作,现在hotspot内置了这个虚拟机。exact vm是为了解决上个虚拟机不能同时使用解释器和编译器的问题,它可以知道内存中某个位置的数据是什么类型具备热点探测,能混合工作的雏形特点,但可惜英雄命短,在solaris 平台短暂使用后,hotspot就凭空出现替换了他。hotspot vm是由一家小公司设计的,后来被sun公司收购,jdk1.3的时候就成为了默认虚原创 2021-10-07 12:13:59 · 408 阅读 · 0 评论 -
jvm cpu占用过高实例以及排查方法
起因在项目现场发现,程序运行的过程中,发现会时不时有cpu占用400%以上的情况,而通过界面很难定位到触发了哪里导致的,不能缩小分析范围。收集数据于是使用了以下几种方式采集数据:1、对jar包配置jmx参数进行暴露,在重启即可使用jdk的jvisualvm.exe进行远程监控2、下载阿里的arthas进行监控。以上两种方式的使用方法就不多说了,请大家自行百度。分析一般对于jvm问题,不外乎就两种表现现象,一种就是堆内存占太多没有被释放,一种就是cpu占用过高。堆内存太多导致堆溢出的原因有很原创 2021-06-25 08:07:22 · 6327 阅读 · 1 评论