JVM总结 阳光穿透心脏的1/2处 2023-09-30 13:13 23阅读 0赞 **目录** 一,Java虚拟机 1.概念 2.作用 3.运行流程 二,运行时数据区域 理解线程私有 1.Java虚拟机栈(线程私有) 作用 栈帧的组成 2.本地方法栈(线程私有) 3.程序计数器(线程私有) 作用 4.堆区(线程共享) 作用 5.方法区(线程共享) 作用 三,内存布局的异常问题 1.内存溢出 概念 原因/什么情况下会导致 结果 解决方法 2.内存泄漏 概念 原因/什么情况下会导致 结果 解决方法 3.栈溢出 概念 原因 解决方法 四,JVM类加载 1.类加载时机 2.类加载过程 3.双亲委派机制 概念 作用 类型 优缺点 破坏双亲委派机制 五,垃圾回收 1.死亡对象的算法 1)引用计数法 2)可达性分析 2.垃圾回收算法 1)标记-清除算法 2)复制算法 3)标记-整理算法 4)分代算法 3.垃圾收集器 1)ParNew + Parallel Scavenge 新生代收集器,使用复制算法 2)Parallel Old 老年代收集器:标记整理算法 3)CMS 老年代收集器 六,JMM(内存模型) 内存模型的作用 1.主内存与工作内存 2.内存间的交互操作 操作 happen —before原则 -------------------- ## 一,Java虚拟机 ## ### 1.概念 ### 从硬件层面理解 * 虚拟机是一种抽象化的计算机,通过在实际的计算机上仿真模拟各种计算机功能来实现的 * Java虚拟机有自己完善的硬体架构,如处理器、堆栈、寄存器等,还具有相应的指令系统 * JVM屏蔽了与具体操作系统平台相关的信息,使得Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行 从进程的角度理解 * 启动一个Java进程 * 会创建一个Java虚拟机 * 并加载class字节码文件 * 运行时翻译机器码,让cpu执行 ### 2.作用 ### * Java中的所有类,必须被装载到JVM中才能运行,这个装载工作是由jvm中的类装载器完成的,类装载器所做的工作实质是把类文件从硬盘读取到内存中 * JVM就是我们常说的java虚拟机,它是整个java实现跨平台的最核心的部分,所有的java程序会首先被编译为.class的类文件,这种类文件可以在虚拟机上执行(也就是说class并不直接与机器的操作系统相对应,而是经过虚拟机间接与操作系统交互,由虚拟机将程序解释给本地系统执行) ### 3.运行流程 ### ![watermark_type_d3F5LXplbmhlaQ_shadow_50_text_Q1NETiBAb2hhbmHvvIE_size_20_color_FFFFFF_t_70_g_se_x_16][] ## 二,运行时数据区域 ## ![watermark_type_d3F5LXplbmhlaQ_shadow_50_text_Q1NETiBAb2hhbmHvvIE_size_20_color_FFFFFF_t_70_g_se_x_16 1][] ### 理解线程私有 ### 由于JVM的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现,因此在任何一个确定的时刻,一个处理器(多核处理器则指的是一个内核)都只会执行一条线程中的指令。因此为了切换线程后能恢复到正确的执行位置,每条线程都需要独立的程序计数器,各条线程之间计数器互不影响,独立存储。我们就把类似这类区域称之为"线程私有"的内存 ### 1.Java虚拟机栈(线程私有) ### #### 作用 #### * Java 虚拟机栈的生命周期和线程相同,Java 虚拟机栈描述的是 Java 方法执行的内存模型 * 每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息 * 常说的堆内存、栈内存中,栈内存指的就是虚拟机栈 #### 栈帧的组成 #### ![watermark_type_d3F5LXplbmhlaQ_shadow_50_text_Q1NETiBAb2hhbmHvvIE_size_20_color_FFFFFF_t_70_g_se_x_16 2][] 1. **局部变量表**: 存放了编译器可知的各种基本数据类型(8大基本数据类型)、对象引用。局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在帧中分配多大的局部变量空间是完全确定的,在执行期间不会改变局部变量表大小。简单来说就是存放方法参数和局部变量 2. **操作数栈**:每个方法会生成一个先进后出的操作栈 3. **动态链接**:指向运行时常量池的方法引用 4. **方法返回地址**:PC 寄存器的地址 ### 2.本地方法栈(线程私有) ### 本地方法栈和虚拟机栈类似,只不过 Java 虚拟机栈是给 JVM 使用的,而本地方法栈是给本地方法使用的 ### 3.程序计数器(线程私有) ### #### 作用 #### 用来记录当前线程执行的行号的 * 程序计数器是一块比较小的内存空间,可以看做是当前线程所执行的字节码的行号指示器。 * 如果当前线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址; * 如果正在执行的是一个Native方法,这个计数器值为空。 * 程序计数器内存区域是唯一一个在JVM规范中没有规定任何OOM情况的区域! ### 4.堆区(线程共享) ### #### 作用 #### 程序创建的所有对象都在堆中保存 * 堆里面分为两个区域:新生代和老生代,新生代放新建的对象,当经过一定 GC 次数之后还存活的对象会放入老生代。新生代还有 3 个区域:一个 Endn + 两个 Survivor(S0/S1) ![watermark_type_d3F5LXplbmhlaQ_shadow_50_text_Q1NETiBAb2hhbmHvvIE_size_16_color_FFFFFF_t_70_g_se_x_16][] ### 5.方法区(线程共享) ### #### 作用 #### 用来存储被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据的 * jdk1.7时,方法区是在Java进程的内存中 * jdk1.8时,是叫元空间,属于本地内存(不在Java进程中) ## 三,内存布局的异常问题 ## ### 1.内存溢出 ### #### 概念 #### 某个运行时数据区域,如果创建的数据,内存不足,就会造成OOM(内存溢出) #### 原因/什么情况下会导致 #### 1. 内存中加载的数据量过于庞大,如一次从数据库取出过多数据 2. 集合类中有对对象的引用,使用完后未清空,使得JVM不能回收 3. 代码中存在死循环或循环产生过多重复的对象实体 4. 使用的第三方软件中的BUG 5. 启动参数内存值设定的过小 #### 结果 #### 会导致程序异常 #### 解决方法 #### * 优化空间利用率 * 加大堆的内存 ### 2.内存泄漏 ### #### 概念 #### 没有用的数据,一直占用内存,无法被gc #### 原因/什么情况下会导致 #### 1. io资源未关闭,多个用户都未关闭时,就会造成内存泄漏 2. 单例模式造成的内存泄露 #### 结果 #### * 内存泄漏太多,就会造成内存溢出 * 常发性内存泄漏。发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏 * 偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的 * 一次性内存泄漏。发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块仅且一块内存发生泄漏。比如,在类的构造函数中分配内存,在析构函数中却没有释放该内存,所以内存泄漏只会发生一次 * 隐式内存泄漏。程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏 #### 解决方法 #### 1. 从程序本身入手,定时清理不使用的数据 2. 使用软引用或是弱引用 3. 加大内存 4. 定时重启程序 ### 3.栈溢出 ### #### 概念 #### 栈一般默认为1-2m,一旦出现死循环或者是大量的递归调用,在不断的压栈过程中,造成栈容量超过1m而导致溢出 #### 原因 #### 对于一台服务器而言,每一个用户请求,都会产生一个线程来处理这个请求,每一个线程对应着一个栈,栈会分配内存,此时如果请求过多,这时候内存不够了,就会发生栈内存溢出 #### 解决方法 #### * 用栈把递归转换成非递归 * 使用静态对象替代非静态局部对象 * 增大堆栈大小值 ![watermark_type_d3F5LXplbmhlaQ_shadow_50_text_Q1NETiBAb2hhbmHvvIE_size_17_color_FFFFFF_t_70_g_se_x_16][] ## 四,JVM类加载 ## ### 1.类加载时机 ### 1)Java 类名 :Java程序的的入口类,需要先执行类加载,在执行main() 2)运行时,执行静态方法调用,静态变量操作等 3)new 对象的时候 4)通过反射创建一个类对象,然后就可以再通过反射,生成实例对象,或调用静态方法 ### 2.类加载过程 ### ![watermark_type_d3F5LXplbmhlaQ_shadow_50_text_Q1NETiBAb2hhbmHvvIE_size_20_color_FFFFFF_t_70_g_se_x_16 3][] 加载:加载class字节码(二进制数据)到方法区,在堆中,生成一个Class类对象 验证:验证class字节码数据,是否安全,以及是否符合Java虚拟机规范 准备:静态变量设置为初始值(对象初始值就是null,基础数据类型,就是对应的初始值)常量 (final修饰的)会设置为真实的值 解析:将常量池内的符号引用替换为直接引用的过程,也就是初始化常量的过程 初始化:静态变量真正的初始化赋值,静态代码块初始化 ### 3.双亲委派机制 ### #### 概念 #### 不直接执行当前类加载器,而是先要查找当前类加载器的父类加载器,父类加载器也是类似的,先找父类,直到找到最顶层的类加载器,开始执行类加载,(找到class类就进行,找不到就交给下一级类加载器) #### 作用 #### * 除了顶层的启动类加载器,其他的类加载器在加载之前,都会委派给它的父加载器进行加载,一层层向上传递,直到所有父类加载器都无法加载,自己才会加载该类。 * 双亲委派模型,更好地解决了各个类加载器协作时基础类的一致性问题,避免类的重复加载;防止核心API库被随意篡改 #### 类型 #### * 启动类加载器(Bootstrp ClassLoader),加载 /lib/rt.jar、-Xbootclasspath * 扩展类加载器(Extension ClassLoader)sun.misc.Launcher$ExtClassLoader,加载 /lib/ext、java.ext.dirs * 应用程序类加载器(Application ClassLoader,sun.misc.Launcher$AppClassLoader),加载 CLASSPTH、-classpath、-cp、Manifest * 自定义类加载器 #### 优缺点 #### **好处:** 确保安全,如Object,String类等,都是使用jdk提供的类,而不是使用自己定义的java.lang.Object **缺点:** 保证了安全,但扩展性就没那么好了(灵活性降低) #### 破坏双亲委派机制 #### * JNDI 通过引入线程上下文类加载器,可以在 Thread.setContextClassLoader 方法设置,默认是应用程序类加载器,来加载 SPI 的代码。有了线程上下文类加载器,就可以完成父类加载器请求子类加载器完成类加载的行为。打破的原因,是为了 JNDI 服务的类加载器是启动器类加载,为了完成高级类加载器请求子类加载器(即上文中的线程上下文加载器)加载类。 * Tomcat,应用的类加载器优先自行加载应用目录下的 class,并不是先委派给父加载器,加载不了才委派给父加载器。打破的目的是为了完成应用间的类隔离。 * OSGi,实现模块化热部署,为每个模块都自定义了类加载器,需要更换模块时,模块与类加载器一起更换。其类加载的过程中,有平级的类加载器加载行为。打破的原因是为了实现模块热替换。 ## 五,垃圾回收 ## ### 1.死亡对象的算法 ### #### 1)引用计数法 #### **概念** 每当堆中多一个引用时,计数器+1,少一个,计数器-1 **缺陷** 无法解决循环引用问题 #### 2)可达性分析 #### **核心思想** * 通过一系列称为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径称之为"引用链",当一个对象到GC Roots没有任何的引用链相连时(从GC Roots到这个对象不可达)时,证明此对象是不可用的 * 对象Object5-Object7之间虽然彼此还有关联,但是它们到GC Roots是不可达的,因此他们会被判定为可回收对象 ![watermark_type_d3F5LXplbmhlaQ_shadow_50_text_Q1NETiBAb2hhbmHvvIE_size_16_color_FFFFFF_t_70_g_se_x_16 1][] ### 2.垃圾回收算法 ### #### 1)标记-清除算法 #### **概念** 分为“标记”和“清除”两个阶段 标记:标记需要gc的对象 清楚:使用gc,将标记好的对象回收 **缺陷** (1)效率低 (2)内存碎片:存放对象时,即使可用空间足够,但连续空间不足,也会触发另一次的gc ![watermark_type_d3F5LXplbmhlaQ_shadow_50_text_Q1NETiBAb2hhbmHvvIE_size_17_color_FFFFFF_t_70_g_se_x_16 1][] #### 2)复制算法 #### **概念** 把用的内存划分为两块一样大小的空间,每次只使用其中一块,把存活的对象复制到另一块空间,然后把之前使用的空间清空 **优点**:清空半区的效率高,不会出现内存碎片 **缺点**:内存利用率低(不会超过50%) #### 3)标记-整理算法 #### 类似于标记清楚算法,采取的方案是将存活的对象,移动到连续的空间,再清空剩余的空间 优点:不会出现内存碎片的问题 #### 4)分代算法 #### 在堆中,根据对象创建及回收的特性,分为了两块区域: **(1)新生代** Eden(E区),2个Survivor(S区) **原因**:对象朝生夕死,很快的创建的,由很快的变为不可用的垃圾 **采取的算法:**复制算法 **过程**:如果出现S区不够的情况,老年代担保,可将数据存放到老年代 1. 当Eden区满的时候,会触发第一次Minor gc,把还活着的对象拷贝到Survivor From区;当Eden区再次触发Minor gc的时候,会扫描Eden区和From区域,对两个区域进行垃圾回收,经过这次回收后还存活的对象,则直接复制到To区域,并将Eden和From区域清空。 2. 当后续Eden又发生Minor gc的时候,会对Eden和To区域进行垃圾回收,存活的对象复制到From区域,并将Eden和To区域清空。 3. 部分对象会在From和To区域中来回复制,如此交换15次(由JVM参数MaxTenuringThreshold决定,这个参数默认是15),最终如果还是存活,就存入到老年代 ![watermark_type_d3F5LXplbmhlaQ_shadow_50_text_Q1NETiBAb2hhbmHvvIE_size_16_color_FFFFFF_t_70_g_se_x_16 2][] **(2)老年代** 对象可能长期存活 采取的算法:标记清除算法,标记整理算法 (3)新生代GC vs 老年代GC ![watermark_type_d3F5LXplbmhlaQ_shadow_50_text_Q1NETiBAb2hhbmHvvIE_size_20_color_FFFFFF_t_70_g_se_x_16 4][] ### 3.垃圾收集器 ### 从Java应用程序来说:大略上,可以分为2种类型 (1)用户体验优先(实时性要求比较高):用户要使用的程序,系统每次STW的时间最少,总的 STW的时间可能变多 ——ParNew(新生代)+CMS(老年代) G1 (2)吞吐量优先(批处理任务):用户不使用的,之执行任务的,总的STW时间最少 ——Parallel Scavenge (新生代)+ Parallel Old (老年代) #### 1)ParNew + Parallel Scavenge 新生代收集器,使用复制算法 #### #### 2)Parallel Old 老年代收集器:标记整理算法 #### #### 3)CMS 老年代收集器 #### 特性:用户体验优先(并发收集,低停顿) 采取”标记清除“算法 ![watermark_type_d3F5LXplbmhlaQ_shadow_50_text_Q1NETiBAb2hhbmHvvIE_size_20_color_FFFFFF_t_70_g_se_x_16 5][] 缺陷 * cpu比较敏感:gc线程需要cpu资源,相对就需要更多的cpu资源 * 无法处理浮动垃圾 * 内存碎片问题 4)G1 全堆收集器 用户体验优先 内存划分:把堆划分为相等的很多个区域,每个区域根据需要设置为E,S,T(老年代) 算法:整体上看基于”标记整理算法“,局部上看基于”复制算法“ ![watermark_type_d3F5LXplbmhlaQ_shadow_50_text_Q1NETiBAb2hhbmHvvIE_size_20_color_FFFFFF_t_70_g_se_x_16 6][] ![watermark_type_d3F5LXplbmhlaQ_shadow_50_text_Q1NETiBAb2hhbmHvvIE_size_17_color_FFFFFF_t_70_g_se_x_16 2][] ## 六,JMM(内存模型) ## ### 内存模型的作用 ### 不同硬件及操作系统,对内存的访问操作也不同,Java采取统一的Java内存模型来屏蔽以上的差异 ### 1.主内存与工作内存 ### 主内存:线程共享的,Java进程的内存 工作内存:线程私有的,cpu执行线程指令时,使用寄存器来保存上下文 ### 2.内存间的交互操作 ### #### 操作 #### 1. lock(锁定) : 作用于主内存的变量,它把一个变量标识为一条线程独占的状态 2. unlock(解锁) : 作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定。 3. read(读取) : 作用于主内存的变量,它把一个变量的值从主内存传输到线程的工作内存中,以便随后的load动作使用。 4. load(载入) : 作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中。 5. use(使用) : 作用于工作内存的变量,它把工作内存中一个变量的值传递给执行引擎。 6. assign(赋值) : 作用于工作内存的变量,它把一个从执行引擎接收到的值赋给工作内存的变量。 7. store(存储) : 作用于工作内存的变量,它把工作内存中一个变量的值传送到主内存中,以便后续的write操作使用。 8. write(写入) : 作用于主内存的变量,它把store操作从工作内存中得到的变量的值放入主内存的变量中 #### happen —before原则 #### **如果两个操作的执行次序无法从happens-before原则推导出来,那么它们就不能保证它们的有序性,虚拟机可以随意地对它们进行重排序** * 程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作 * 锁定规则:一个unLock操作先行发生于后面对同一个锁的lock操作 * volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作 * 传递规则:如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C * 线程启动规则:Thread对象的start()方法先行发生于此线程的每个一个动作 * 线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生 * 线程终结规则:线程中所有的操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行 * 对象终结规则:一个对象的初始化完成先行发生于他的finalize()方法的开始 [watermark_type_d3F5LXplbmhlaQ_shadow_50_text_Q1NETiBAb2hhbmHvvIE_size_20_color_FFFFFF_t_70_g_se_x_16]: https://img-blog.csdnimg.cn/b08329d626fb4aca82825ca8774ab8d5.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAb2hhbmHvvIE=,size_20,color_FFFFFF,t_70,g_se,x_16 [watermark_type_d3F5LXplbmhlaQ_shadow_50_text_Q1NETiBAb2hhbmHvvIE_size_20_color_FFFFFF_t_70_g_se_x_16 1]: https://img-blog.csdnimg.cn/75d1ff109a6547f5bac54171f8cd2948.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAb2hhbmHvvIE=,size_20,color_FFFFFF,t_70,g_se,x_16 [watermark_type_d3F5LXplbmhlaQ_shadow_50_text_Q1NETiBAb2hhbmHvvIE_size_20_color_FFFFFF_t_70_g_se_x_16 2]: https://img-blog.csdnimg.cn/e0d488144cca4b2d9db130e06c72f40a.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAb2hhbmHvvIE=,size_20,color_FFFFFF,t_70,g_se,x_16 [watermark_type_d3F5LXplbmhlaQ_shadow_50_text_Q1NETiBAb2hhbmHvvIE_size_16_color_FFFFFF_t_70_g_se_x_16]: https://img-blog.csdnimg.cn/7aab9427f9f448588fab8a17f2c9bdef.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAb2hhbmHvvIE=,size_16,color_FFFFFF,t_70,g_se,x_16 [watermark_type_d3F5LXplbmhlaQ_shadow_50_text_Q1NETiBAb2hhbmHvvIE_size_17_color_FFFFFF_t_70_g_se_x_16]: https://img-blog.csdnimg.cn/63091bb6c0244115968bee6c50600d78.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAb2hhbmHvvIE=,size_17,color_FFFFFF,t_70,g_se,x_16 [watermark_type_d3F5LXplbmhlaQ_shadow_50_text_Q1NETiBAb2hhbmHvvIE_size_20_color_FFFFFF_t_70_g_se_x_16 3]: https://img-blog.csdnimg.cn/e74f90f3ac6144f990b51567ecb94282.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAb2hhbmHvvIE=,size_20,color_FFFFFF,t_70,g_se,x_16 [watermark_type_d3F5LXplbmhlaQ_shadow_50_text_Q1NETiBAb2hhbmHvvIE_size_16_color_FFFFFF_t_70_g_se_x_16 1]: https://img-blog.csdnimg.cn/5ac35b67a1364becb8180b7c9fad40ef.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAb2hhbmHvvIE=,size_16,color_FFFFFF,t_70,g_se,x_16 [watermark_type_d3F5LXplbmhlaQ_shadow_50_text_Q1NETiBAb2hhbmHvvIE_size_17_color_FFFFFF_t_70_g_se_x_16 1]: https://img-blog.csdnimg.cn/51e399529bcd434580195e74c4d66465.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAb2hhbmHvvIE=,size_17,color_FFFFFF,t_70,g_se,x_16 [watermark_type_d3F5LXplbmhlaQ_shadow_50_text_Q1NETiBAb2hhbmHvvIE_size_16_color_FFFFFF_t_70_g_se_x_16 2]: https://img-blog.csdnimg.cn/28441c953c414bc587bf9ec14d4676fe.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAb2hhbmHvvIE=,size_16,color_FFFFFF,t_70,g_se,x_16 [watermark_type_d3F5LXplbmhlaQ_shadow_50_text_Q1NETiBAb2hhbmHvvIE_size_20_color_FFFFFF_t_70_g_se_x_16 4]: https://img-blog.csdnimg.cn/7a6161314395475da3a2cdbaba089b3b.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAb2hhbmHvvIE=,size_20,color_FFFFFF,t_70,g_se,x_16 [watermark_type_d3F5LXplbmhlaQ_shadow_50_text_Q1NETiBAb2hhbmHvvIE_size_20_color_FFFFFF_t_70_g_se_x_16 5]: https://img-blog.csdnimg.cn/d7e69bec93cc4f818c99ac1cc1b88a13.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAb2hhbmHvvIE=,size_20,color_FFFFFF,t_70,g_se,x_16 [watermark_type_d3F5LXplbmhlaQ_shadow_50_text_Q1NETiBAb2hhbmHvvIE_size_20_color_FFFFFF_t_70_g_se_x_16 6]: https://img-blog.csdnimg.cn/cd107e4eedd74836a918bcdc46fd1de0.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAb2hhbmHvvIE=,size_20,color_FFFFFF,t_70,g_se,x_16 [watermark_type_d3F5LXplbmhlaQ_shadow_50_text_Q1NETiBAb2hhbmHvvIE_size_17_color_FFFFFF_t_70_g_se_x_16 2]: https://img-blog.csdnimg.cn/10a7dc0086764b0a9b23eb30b0572da0.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAb2hhbmHvvIE=,size_17,color_FFFFFF,t_70,g_se,x_16
相关 jvm总结 *目录** 1、什么情况下会发生堆、栈内存溢出。 2、JVM的内存结构,Eden和Survivor比例。 3、JVM内存为什么要分成新生代,老年代,持久代。新生代中... 刺骨的言语ヽ痛彻心扉/ 2024年04月17日 05:48/ 0 赞/ 79 阅读
相关 JVM总结 目录 一,Java虚拟机 1.概念 2.作用 3.运行流程 二,运行时数据区域 理解线程私有 1.Java虚拟机栈(线程私有) 作用 栈帧的组成 2.本地 阳光穿透心脏的1/2处/ 2023年09月30日 13:13/ 0 赞/ 24 阅读
相关 JVM总结 常见面试题 请你谈谈你对JVM的理解? java8虚拟机和之前的变化和更新 什么是OOM?什么是栈溢出?怎么分析? JVM常见的调优参数有哪些? Dear 丶/ 2023年07月12日 14:08/ 0 赞/ 27 阅读
相关 jvm总结 学习JVM的目的也很简单: 能够知道JVM是什么,为我们干了什么,具体是怎么干的。能够理解到一些初学时不懂的东西 在面试的时候有谈资 能装逼 一、简单聊 一时失言乱红尘/ 2023年06月19日 07:19/ 0 赞/ 22 阅读
相关 JVM总结 目录 1.什么是JVM 2.JVM基本结构 3.运行时数据区 4 hotspot方法区的实现 5 堆的结构 6 为何新生代要设置两个survivor区 7 对象访 桃扇骨/ 2023年01月01日 06:51/ 0 赞/ 161 阅读
相关 jvm总结 ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQy 旧城等待,/ 2022年12月27日 14:29/ 0 赞/ 206 阅读
相关 JVM 总结 [初期预调优][Link 1] JVM总结: 一、理论 一、JVM内存模型: 二、JVM垃圾回收机制(从新生代和老年代的角度分析): 三、JVM调优经历:[调优实战][ 向右看齐/ 2022年10月27日 12:17/ 0 赞/ 188 阅读
相关 JVM总结 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_Q1NETiBA5LiA54K55Y2a5a6i_ r囧r小猫/ 2022年09月08日 10:26/ 0 赞/ 177 阅读
相关 jvm总结 一、JVM结构 JVM是可运行Java代码的假想计算机 ![70][] 1.1 类加载器 1.2 执行引擎:执行包在装载类的方法中的指令,也就是方法,clas 矫情吗;*/ 2022年05月20日 05:13/ 0 赞/ 179 阅读
还没有评论,来说两句吧...