当前位置: 首页 > news >正文

JVM系列 | 对象的消亡——HotSpot的设计细节

HotSpot 的细节实现

文章目录

  • HotSpot 的细节实现
    • OopMap 与 根节点枚举
      • 根节点类型及说明
      • HotSpot中的实现
    • OopMap 与 安全点
      • 安全点介绍
      • 如何保证程序在安全点上?
    • 安全区域
    • 记忆集与卡表
      • 记忆集
      • 卡表
    • 写屏障
    • 并发的可达性分析(与用户线程)
      • 并发可达性分析 存在的问题
      • 解决方案

笔者寄语:这一篇博客真的写的脑壳痛,很多地方太抽象了,想要仔细的扣细节很费脑袋,本来早就想发布了,但是因为要扣的点太多了,一直拖到了现在。

OopMap 与 根节点枚举

无论是标记复制算法、标记整理算法、标记清除算法,都需要有一个从“根节点”开始的可达性分析工序,因此确定出哪些节点是根节点就很重要。

根节点类型及说明

  1. 全局静态变量(Global Static Variables)
  • 共享和生命周期长:全局静态变量在整个程序生命周期内都是存在的,它们在程序的任何部分都可以被访问。
  • 可达性:因为全局静态变量可以引用任何对象,并且这些对象可能被多个线程使用,所以它们必须作为根节点来追踪。
  1. 栈帧中的局部变量(Local Variables in Stack Frames)
  • 活动性:这些是当前正在执行的方法或函数中的局部变量。因为它们正在被使用,所以引用的对象不能被回收。
    可达性:这些局部变量在栈帧中存储,GC需要从这些变量开始追踪,以确保它们引用的对象不会被回收。
  1. 当前使用中的线程(Currently Active Threads)
  • 线程对象:每个活动的线程对象都会被作为根节点,因为线程本身以及它们的栈帧包含的局部变量和执行上下文需要被追踪。
  1. JNI引用(JNI References)
  • 本地方法接口:在使用Java本地接口(JNI)调用本地代码时,本地代码可以创建引用指向Java对象,这些引用也必须作为根节点来追踪,以确保这些Java对象在本地代码使用期间不会被回收。
  1. 类加载器(Class Loaders)
  • 类和静态变量的管理:类加载器是负责加载Java类的对象,它们持有对类和静态变量的引用,因此它们的引用链必须被追踪,以确保这些类和静态变量不会被错误地回收。
  1. 系统类(System Classes)
  • 核心类库:Java中的一些核心类库,例如java.lang.System、java.lang.Thread等,持有对大量静态变量和对象的引用,这些系统类也必须作为根节点来追踪。
  1. GC Roots in Java Heap (某些Java堆中的对象)
  • 常量池(String Pool):常量池中的字符串对象,以及一些其他常量值会被作为根节点来追踪。
  • 类静态字段(Static Fields of Classes):静态字段属于类的对象,它们在类加载时被创建,在类卸载时被回收。

HotSpot中的实现

在HotSpot中进行垃圾回收的第一个步骤就是“根节点枚举”,根节点枚举的过程必须要停止用户线程(也就是停止代码程序),这一步骤被称为"Stop The World"(时停/酷);且现在程序一般都非常的大,堆等内存动辄几百上千M,如果要一个个对象扫描来判断类型的话耗时实在是可观,因此这种操作肯定是不可取的。

HotSpot为了解决这一问题,引入了OopMap:一旦类加载动作完成的时候,HotSpot就会把对象内什么偏移量上是什么类型的数据计算出来,在即时编译过程中,也会在特定的位置记录下栈里和寄存器里哪些位置是引用。

如何理解偏移量呢?就是与这个类的起始地址的差,也就是从开头向后数多少个地址是一个什么类型的数据。

这样一来,JVM就无需扫描整个运行时内存空间,而是直接扫描OopMap就可以获得当前运行时内存有哪些根节点,从而解约根节点枚举时的时间。

OopMap 与 安全点

安全点介绍

《深入理解Java虚拟机:原文》可能导致引用关系变化,或者说导致OopMap内容变化的指令非常多,如果为每一条指令都生成对应的OopMap,那将会需要大量的额外存储空间,这样垃圾收集伴随而来的空间成本就会变得无法忍受的高昂。

可见,引如OopMap并无问题,我们还需要解决什么时候更新OopMap的问题:过多的安全点会导致性能开销过大,而过少的安全点会导致垃圾收集或其他全局操作无法及时执行…经过JVM团队深思熟虑,终于给出了解决方案:在所有线程进入某些特定代码位置之后更新OopMap(通常更新完成之后直接进行垃圾收集操作),这些特定位置就被称为安全点

安全点通常是:

  1. 循环的回边(一次循环结束后 回到循环开始的位置 这两者之间)

  2. 方法的开始与结束

  3. 抛异常的位置

下面用代码进行一个简单的实力

public class GCExample {private static Object staticObject = new Object();public static void main(String[] args) {Object localObject = new Object();// 模拟一个循环,其中可能触发安全点for (int i = 0; i < 1000000; i++) {// 模拟方法调用和循环迭代someMethod(localObject);}// 主线程请求垃圾收集System.gc();}private static void someMethod(Object obj) {// 模拟方法调用,可能插入安全点System.out.println("Processing: " + obj);}
}

如何保证程序在安全点上?

要在进行垃圾回收的时候,保证所有的线程都停留在安全点上,有两种方式:

  1. 抢占式
  2. 主动式

抢先式中断不需要线程的执行代码主动去配合,在垃圾收集发生时,系统首先把所有用户线程全部中断,如果发现有用户线程中断的地方不在安全点上,就恢复这条线程执行,让它一会再重新中断,直到跑到安全点上。现在几乎没有虚拟机实现采用抢先式中断来暂停线程响应GC事件。

主动式中断的思想是当垃圾收集需要中断线程的时候,不直接对线程操作,仅仅简单地设置一个标志位,各个线程执行过程时会不停地主动去轮询这个标志,一旦发现中断标志为真时就自己在最近的安全点上主动中断挂起。轮询标志的地方和安全点是重合的,另外还要加上所有创建对象和其他需要在Java堆上分配内存的地方,这是为了检查是否即将要发生垃圾收集,避免没有足够内存分配新对象。

由于轮询操作在代码中会频繁出现,这要求它必须足够高效。HotSpot使用内存保护陷阱的方式(自陷陷阱),关于自陷陷阱这里不多赘述,可以自己搜一下。

安全区域

针对一些无法进入安全点的线程(如Sleep或Blocked的线程),虚拟机设置了安全区域来应对。

安全区域是指能够确保在某一段代码片段之中,引用关系不会发生变化,因此,在这个区域中任意地方开始垃圾收集都是安全的。我们也可以把安全区域看作被扩展拉伸了的安全点。

记忆集与卡表

记忆集

万事俱备,接下来似乎要进行垃圾回收了,这里又有一个问题,如果存在跨代引用怎么办?

跨代引用是指老年代中的对象引用年轻代中的对象,或者反过来年轻代引用老年代。由于垃圾收集是分代进行操作的,老年代的收集频率远低于年轻代,那么在对年轻代进行垃圾收集的时候,如果一个老年代的对象O引用了年轻代对象Y,而JVM并不知道这一点,在扫描完整个年轻代之后发现没有对象引用对象Y,这时候将Y给销毁了,就会造成程序运行错误。

如何解决这一点问题?JVM给出的答案是:采用一块专门的内存区域用于记录哪一些对象发生了跨代引用,这便是记忆集

比如如果老年代O引用了年轻代的Y,那么就在记忆集中记录下O对Y的引用,这样在对年轻代进行垃圾收集的时候(我是指标记阶段),就能顺便给O也带进来标记一下,这样便能标记到Y。反之亦是如此。

卡表

但是JVM团队还是觉得这样的记录太过于浪费内存空间,如果存在大量的跨代引用的话,使用的内存空间确实十分可观,因此JVM团队决定放大粒度,一般来说,存在以下三个精度:

  1. 字长精度:每个记录精确到一个机器字长(就是处理器的寻址位数,如常见的32位或64位,这个精度决定了机器访问物理内存地址的指针长度),该字包含跨代指针

  2. 对象精度:每个记录精确到一个对象,该对象里有字段含有跨代指针

  3. 卡精度:每个记录精确到一块内存区域,该区域内有对象含有跨代指针

卡精度就是卡表,使用卡精度,JVM将不再记录内存或对象,而是记录一个大致的范围,在这个内存范围内存在跨代引用,在进行垃圾回收的时候,只需要额外将这一块内存区域也扫描进去即可。

在这里插入图片描述

比如这张图中,由于O7所在的内存区域与O20所在的内存区域存在对新生代的跨带引用,因此对新生代进行垃圾回收的时候,也会将上图两个红色的区域算进去。


*在一些新的垃圾回收器中不存在年轻代与老年代,而是使用了更复杂的区域收集,也会涉及跨带引用

写屏障

写屏障是十分好理解的,在这里就引用一些原文内容了,简单来说就是指令层面的AOP操作。

写屏障可以看作在虚拟机层面对“引用类型字段赋值”这个动作的AOP切面,在引用对象赋值时会产生一个环形(Around)通知,供程序执行额外的动作,也就是说赋值的前后都在写屏障的覆盖范畴内。在赋值前的部分的写屏障叫作写前屏障(Pre-Write Barrier),在赋值后的则叫作写后屏障(Post-Write Barrier)。HotSpot虚拟机的许多收集器中都有使用到写屏障,但直至G1收集器出现之前,其他收集器都只用到了写后屏障。

应用写屏障后,虚拟机就会为所有赋值操作生成相应的指令,一旦收集器在写屏障中增加了更新卡表操作,无论更新的是不是老年代对新生代对象的引用,每次只要对引用进行更新,就会产生额外的开销,不过这个开销与Minor GC时扫描整个老年代的代价相比还是低得多的。


除了写屏障的开销外,卡表在高并发场景下还面临着“伪共享”(False Sharing)问题。伪共享是处理并发底层细节时一种经常需要考虑的问题,现代中央处理器的缓存系统中是以缓存行(Cache Line)为单位存储的,当多线程修改互相独立的变量时,如果这些变量恰好共享同一个缓存行,就会彼此影响(写回、无效化或者同步)而导致性能降低,这就是伪共享问题。

假设处理器的缓存行大小为64字节,由于一个卡表元素占1个字节,64个卡表元素将共享同一个缓存行。这64个卡表元素对应的卡页总的内存为32KB(64×512字节),也就是说如果不同线程更新的对象正好处于这32KB的内存区域内,就会导致更新卡表时正好写入同一个缓存行而影响性能。为了避免伪共享问题,一种简单的解决方案是不采用无条件的写屏障,而是先检查卡表标记,只有当该卡表元素未被标记过时才将其标记为变脏。

并发的可达性分析(与用户线程)

解决了根节点枚举、安全点、记忆集、写屏障之后,终于可以进行可达性分析了。

在最初的垃圾收集器中(如Serial、ParNew收集器),在进行可达性分析的时候都需要暂停用户线程,直到CMS收集器的出现,才终于实现了用户线程与垃圾收集线程共同工作的场景。

小故事:在最初始版本的垃圾收集器中,JVM没执行一段时间都需要Stop The World(时停)进行垃圾收集工作,那时候Java是十分“慢”的,而JVM的开发者们也很委屈:你总不能在你妈妈收拾房间的时候还要乱丢垃圾吧,这样什么时候能打扰完?在你妈妈收拾房间的时候你就应该乖乖坐在沙发上。

并发可达性分析 存在的问题

为了让垃圾回收更快!!就必须要让垃圾回收线程与用户线程同时执行!!但若是用户线程与垃圾收集线程同步进行,那么就可能造成已经扫描过的确定被引用的对象不再被引用了,或者已经扫描过的确定不再被引用的对象又被引用了;这两种情况。这就是我们本章节要弄懂的问题。

为了更好说明对象的引用关系,这里采用三色标记法进行说明:

  1. 黑色:已经被标记是被引用的对象
  2. 白色:未扫描到的对象
  3. 灰色:已经确认被引用,但是还没有扫描它的引用关系的对象

整个图就像是一个波纹,黑色在波纹内,白色在波纹外,灰色是波峰…

在这里插入图片描述

上图前三张图片说明了用户线程在静止状态下的扫描过程;后两张图说明了用户线程与垃圾回收线程同时工作时可能会造成的情况。


注意,如果垃圾回收线程与用户线程并行操作,那么会出现两种情况:

  1. 已经被标记为黑色(被引用)的对象突然不再引用了(浮动垃圾)
  2. 已经被标记为白色(未被引用)的对象突然被引用了(危险!!)

如果是情况1的话,这些对象不被清理问题不大,顶多是占用一些内存,产生一些“浮动垃圾”,但如果是情况2对象小时,那么就很危险了,原本存在引用关系的对象被清除了,那么会造成致命错误,可能会导致程序崩溃。

解决方案

为了解决这一问题,1994年Wilson在理论上证明了,当满足两个条件的时候,才会产生对象消失问题:

  1. 赋值器插入了一条或多条从黑色对象到白色对象的新引用
  2. 赋值器删除了全部从灰色对象到该白色对象的直接或间接引用

这两句话理解起来十分拗口,也就是说,新插入了一个由黑色对象对白色对象的引用关系,且该白色对象(原本就)无法被扫描到(原本就不可达或删除了其可达关系)。

只需要破坏上面的任意一个条件,就不会造成“消失对象”问题。

方法一:增量更新要破坏的是第一个条件,当黑色对象插入新的指向白色对象的引用关系时,就将这个新插入的引用记录下来,等并发扫描结束之后,再将这些记录过的引用关系中的黑色对象为根,重新扫描一次。这可以简化理解为,黑色对象一旦新插入了指向白色对象的引用之后,它就变回灰色对象了。

方法二:原始快照要破坏的是第二个条件,当灰色对象要删除指向白色对象的引用关系时,就将这个要删除的引用记录下来,在并发扫描结束之后,再将这些记录过的引用关系中的灰色对象为根,重新扫描一次。这也可以简化理解为,无论引用关系删除与否,都会按照刚刚开始扫描那一刻的对象图快照来进行搜索。

相关文章:

JVM系列 | 对象的消亡——HotSpot的设计细节

HotSpot 的细节实现 文章目录 HotSpot 的细节实现OopMap 与 根节点枚举根节点类型及说明HotSpot中的实现 OopMap 与 安全点安全点介绍如何保证程序在安全点上&#xff1f; 安全区域记忆集与卡表记忆集卡表 写屏障并发的可达性分析&#xff08;与用户线程&#xff09;并发可达性…...

vue 运行或打包过程报错 JavaScript heap out of memory(内存溢出)

安装 increase-memory-limit npm install increase-memory-limit 运行increase-memory-limit ./node_modules/.bin/increase-memory-limit 运行后会报以下错误&#xff1a; "node --max-old-space-size10240" 不是内部或外部命令&#xff0c;也不是可运行的程序…...

git分支提交方法

先下载最新代码 改动文件覆盖 cp 文件到~/file/ git add添加文件 git commit提交本地 建立分支 git diff .c git status -uno git add git commit git checkout -b issue-lyd git push origin issue-lyd...

从微架构到向量化--CPU性能优化指北

引入 定位程序性能问题&#xff0c;相信大家都有很多很好的办法&#xff0c;比如用top/uptime观察负载和CPU使用率&#xff0c;用dstat/iostat观察io情况&#xff0c;ptrace/meminfo/vmstat观察内存、上下文切换和软硬中断等等&#xff0c;但是如果具体到CPU问题&#xff0c;我…...

声声入耳,事事如意 爱可声「如意」助听器即将上市!

如意助听器 Charm 爱可声全新系列「如意」助听器即将上市&#xff01; 此次新品充分考虑了不同听损以及年龄的用户需求&#xff0c; 融合三大强劲性能。 1、多群体覆盖&#xff0c;定制个性化方案 如意助听器针对不同听损程度的听障患者设计了不同款式助听器&#xff0c;贴…...

生物实验室设备文件采集如何才能质量和效率双管齐下?

生物实验室的设备文件采集是实验室运营、科研活动和数据科学实践应用中不可或缺的一环。通过数据采集&#xff0c;实验室可以优化资源配置、提高实验结果的准确性和可靠性、支持科研水平的提升&#xff0c;并确保数据的安全性和可追溯性。因此&#xff0c;实验室应高度重视设备…...

Framework源码整编、单编、烧录过程

目录 一.背景 二.整编方式 二.单编方式 三.烧录 一.背景 源码编译分为整编和单编,整编通常耗时较长,单编则速度很多,如果我们进行一个小的修改想要立马验证的话单编就很合适 二.整编方式 开始执行编译操作,总共三步. 执行source操作source build/envsetup.sh .执行lunc…...

TypeScript类型断言

TypeScript类型断言是TypeScript中一个强大且有用的特性&#xff0c;它允许开发者在编译时明确指定一个值的类型&#xff0c;即使TypeScript无法自动推断出这个类型。类型断言类似于其他编程语言中的类型转换&#xff0c;但它不会改变变量的运行时值&#xff0c;而只是告诉编译…...

Mallet:一款针对任意协议的安全拦截代理工具

关于Mallet Mallet是一款功能强大的协议安全分析工具&#xff0c;该工具支持针对任意协议创建用于安全审计的拦截代理&#xff0c;该工具本质上与我们所熟悉的拦截Web代理类似&#xff0c;只是通用性更强。 工具运行机制 Mallet建立在Netty框架之上&#xff0c;并且依赖于Net…...

【IEEE出版】第五届大数据、人工智能与软件工程国际研讨会(ICBASE 2024,9月20-22)

第五届大数据、人工智能与软件工程国际研讨会&#xff08;ICBASE 2024&#xff09;将于2024年09月20-22日在中国温州隆重举行。 会议主要围绕大数据、人工智能与软件工程等研究领域展开讨论。会议旨在为从事大数据、人工智能与软件工程研究的专家学者、工程技术人员、技术研发人…...

自修室预约小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;学生管理&#xff0c;公告通知管理&#xff0c;自修室管理&#xff0c;座位预约管理&#xff0c;预约取消管理&#xff0c;管理员管理&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统首页&a…...

用于跟踪个人图书馆的BookLogr

什么是 BookLogr &#xff1f; BookLogr 是一款网络应用&#xff0c;旨在帮助您轻松管理个人图书馆。这项自托管服务可确保您完全控制数据&#xff0c;提供安全且私密的方式来跟踪您拥有、阅读或希望阅读的所有书籍。您也可以选择向公众自豪地展示您的图书馆&#xff0c;与您的…...

深入解析JVM垃圾回收机制:Full GC、Minor GC与Major GC

目录 引言垃圾回收的基本概念 什么是垃圾回收GC的分类JVM内存模型 堆内存非堆内存Minor GC 触发条件运行机制对性能的影响...

Windows10点击文件夹右键卡死的解决办法

1、首先同时按下【WinR】打开运行页面&#xff0c;输入命令【regedit】按下回车或者点击确定。 2、打开注册表编辑器后&#xff0c;定位到如下位置“HKEY_CLASSES_ROOT\Directory\Background\Shellex\ContextMenuHandlers”。 3、然后在其中将所有名为“New”的文件或项全部删…...

C# 设计模式之单例模式

总目录 前言 本文是个人基于C#学习设计模式总结的学习笔记&#xff0c;希望对你有用&#xff01; 1 基本介绍 定义&#xff1a;确保一个类只有一个实例&#xff0c;并提供一个全局访问点。 本质就是保证在整个应用程序的生命周期中&#xff0c;任何一个时刻&#xff0c;单例…...

【组合数学】【Python】【小练习】一、斯特灵近似式求阶乘

一、问题介绍 斯特灵&#xff08;Stirling&#xff09;近似式&#xff0c;是数学分析中&#xff0c;用于求阶乘近似值的一个常用公式&#xff0c;其简单的表述形式为&#xff1a; 二、Python实现 使用Python&#xff0c;循环从n1至n98&#xff0c;分别输出n的阶乘值、斯特灵公…...

【IEEE Fellow特邀报告,JPCS独立出版】第四届电子通信与计算机科学技术国际学术会议(ECCST 2024,9月20-22)

2024年第四届电子通信与计算机科学技术国际学术会议将于2024年9月20-22日在中国上海举行。 会议旨在为从电子与通信、网络、人工智能与计算机技术研究的专家学者、工程技术人员、技术研发人员提供一个共享科研成果和前沿技术&#xff0c;了解学术发展趋势&#xff0c;拓宽研究思…...

DockerCompose部署示例

目录 前言 1. 初识DockerCompose 2. 安装DockerCompose 3. 部署微服务项目 1&#xff09;找一个目录&#xff0c;创建一个新的cloud-demo文件夹。 2&#xff09;在cloud-demo文件夹创建一个docker-compose.yml文件&#xff0c;然后编写下面内容&#xff1a; 3&#xff09…...

【云原生】Helm来管理Kubernetes集群的详细使用方法与综合应用实战

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…...

电源插头应该统一方向

大家在使用插排的时候就会发现&#xff0c;有的横向&#xff0c;有的竖向。 国家强制规定&#xff0c;统一方向&#xff0c;插排能方便使用。...

大学新生编程入门最佳攻略

引言 编程的重要性&#xff1a;简述编程在当今社会的地位&#xff0c;为何它是大学生的必备技能。目标设定&#xff1a;明确文章旨在帮助新生从零基础开始&#xff0c;逐步成长为编程高手。 方向一&#xff1a;编程语言选择 1. 编程语言概览 介绍几种流行语言&#xff1a;如…...

MySQL 的binlog 、undolog 、redolog

Binlog (二进制日志) bin Log 作用 用于记录所有修改数据库数据的 SQL 语句或行级别的变化&#xff0c;主要用于主从复制和数据恢复。 binlog格式 STATEMENT模式&#xff1a;binlog里面记录的就是SQL语句的原文。优点是并不需要记录每一行的数据变化&#xff0c;减少了binlo…...

【计算机网络】三次握手、四次挥手

问&#xff1a;三次握手 四次挥手 TCP 连接过程是 3 次握手&#xff0c;终止过程是 4 次挥手 3次握手 第一步&#xff1a;客户端向服务器发送一个带有 SYN&#xff08;同步&#xff09;标志的包&#xff0c;指示客户端要建立连接。 第二步&#xff1a;服务器收到客户端的请求…...

Spring Boot中的全局异常处理:@RestControllerAdvice的应用

在现代Web开发中&#xff0c;异常处理是一个不可或缺的部分。良好的异常处理不仅能提高系统的健壮性&#xff0c;还能提升用户体验。在Spring Boot中&#xff0c;全局异常处理的实现可以通过使用RestControllerAdvice注解来完成。本文将详细介绍如何使用RestControllerAdvice和…...

指令数据的构建

文章目录 基于现有的 NLP 任务数据集构建基于日常对话数据构建基于合成数据构建指令微调(Instruction Tuning)是指使用自然语言形式的数据对预训练后的大语言模型进行参数微调,这一术语由谷歌研究员在 2022 年的一篇 ICLR 论文中正式提出。在另外一些参考文献中,指令微调也…...

论文解读(14)-GeoCLIP

加油&#xff0c;加油&#xff01; 原文&#xff1a; GeoCLIP: Clip-Inspired Alignment between Locations and Images for Effective Worldwide Geo-localization &#xff08;2309.16020 (arxiv.org)&#xff09; 这一篇的重点在于范围放宽到全球了 摘要 首先指出了目前…...

MySQL基础练习题16-电影评分

题目 准备数据 分析数据 总结 题目 查找评论电影数量最多的用户名。如果出现平局&#xff0c;返回字典序较小的用户名。 查找在 February 2020 平均评分最高 的电影名称。如果出现平局&#xff0c;返回字典序较小的电影名称。 准备数据 ## 创建库 create database db; u…...

CRMEB-众邦科技 使用笔记

1.启动项目报错 Unable to load authentication plugin ‘caching_sha2_password’. 参考&#xff1a;http://t.csdnimg.cn/5EqaE 解决办法&#xff1a;升级mysql驱动 <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</ar…...

npm与webpack的学习笔记

npm 定义&#xff1a;npm是Node.js标准的软件包管理器。它起初是作为下载和管理Node.js包依赖的方式&#xff0c;但其现在也已成为前端JavaScript中使用的工具。 包 包&#xff1a;将模块、代码、其他资料聚合成一个文件夹 包的分类&#xff1a; 项目包&#xff1a;主要用…...

Vue 生命周期选项:2.x 与 3.x 的全面解析及案例分享二

目录 Vue3.X生命周期 介绍 流程图 案例 ​​​​​​​this.$nextTick Vue 生命周期选项:2.x 与 3.x 的全面解析及案例分享一-CSDN博客 Vue3.X生命周期 介绍 beforeCreate:在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。此时无法访…...