JVM字节码与类的加载——类的加载过程详解

news2024/11/23 8:12:30

文章目录

  • 1、概述
  • 2、加载(Loading)阶段
    • 2.1、加载完成的操作
    • 2.2、二进制流的获取方式
    • 2.3、类模型与Class实例的位置
    • 2.4、数组类的加载
  • 3、链接(Linking)阶段
    • 3.1、链接阶段之验证(Verification)
      • 3.1.1、格式检查
      • 3.1.2、字节码的语义检查
      • 3.1.3、字节码验证
      • 3.1.4、符号引用验证
    • 3.2、链接阶段之准备(Preparation)
    • 3.3、链接阶段之解析(Resolution)
  • 4、初始化(Initialization)阶段
    • 4.1、static与final搭配
    • 4.2、<clinit>()方法的线程安全性
    • 4.3、类的初始化时机:主动使用和被动使用
      • 4.3.1、主动使用
      • 4.3.2、被动使用
  • 5、类的使用(Using)
  • 6、类的卸载(Unloading)
    • 6.1、类、类的加载器、类的Class对象、类的实例之间的引用关系
    • 6.2、类的生命周期
    • 6.3、案例
    • 6.4、类的卸载
    • 6.5、回顾:方法区的垃圾回收
  • 7、小结

我们知道class文件是存放在磁盘上的,如果想要在JVM中使用class文件,需要将其加载至内存当中。了解了class文件的结构,本帖将详细介绍class文件加载到内存中的过程。

1、概述

在Java中数据类型分为基本数据类型和引用数据类型。基本数据类型由JVM预先定义,可以直接被用户使用,引用数据类型则需要执行类的加载才可以被用户使用。Java虚拟机规范中规定,class文件加载到内存,再到类卸载出内存会经历7个阶段,分别是加载、验证、准备、解析、初始化、使用和卸载,其中,验证、准备和解析3个阶段统称为链接(Linking),整个过程称为类的生命周期,如下图所示:
在这里插入图片描述

2、加载(Loading)阶段

2.1、加载完成的操作

所谓加载,简而言之就是将Java类的class文件加载到机器内存中,并在内存中构建出Java类的原型,也就是类模板对象。所谓类模板对象,其实就是Java类在JVM内存中的一个快照,JVM将从class文件中解析出的常量池、类字段、类方法等信息存储到类模板对象中。JVM在运行期可以通过类模板对象获取Java类中的任意信息,能够访问Java类中的成员变量,也能调用Java方法,反射机制便是基于这一基础,如果JVM没有将Java类的声明信息存储起来,则JVM在运行期也无法使用反射。在加载类时,JVM必须完成以下3件事情:

  • (1)通过类的全名,获取类的二进制数据流。
  • (2)解析类的二进制数据流为方法区内的数据结构(Java类模型)。
  • (3)创建java.lang.Class类的实例,作为方法区中访问类数据的入口。

2.2、二进制流的获取方式

JVM可以通过多种途径产生或获得类的二进制数据流,下面列举了常见的几种方式:

  • (1)通过文件系统读入一个后缀为.class的文件(最常见)。
  • (2)读入jar、zip等归档数据包,提取类文件。
  • (3)事先存放在数据库中的类的二进制数据。
  • (4)使用类似于HTTP之类的协议通过网络加载。
  • (5)在运行时生成一段Class的二进制信息。

在获取到类的二进制信息后,JVM就会处理这些数据,并最终转为一个java.lang.Class的实例。如果输入数据不是JVM规范的class文件的结构,则会抛出“ClassFormatError”异常。

2.3、类模型与Class实例的位置

1、类模型的位置
加载的类在JVM中创建相应的类结构,类结构会存储在方法区中。
2、Class实例的位置
类加载器将class文件加载至方法区后,会在堆中创建一个Java.lang.Class对象,用来封装类位于方法区内的数据结构,该Class对象是在加载类的过程中创建的,每个类都对应有一个Class类型的对象。类模型和Class实例的位置对应关系如下图所示:
在这里插入图片描述
外部可以通过访问代表Order类的Class对象来获取Order类的数据结构。java.lang.Class类的构造方法是私有的,只有JVM能够创建。java.lang.Class实例是访问类型元数据的入口,也是实现反射的关键数据。通过Class类提供的接口,可以获得目标类所关联的class文件中具体的数据结构、方法、字段等信息。如代码清单如下所示,展示了如何通过java.lang.Class类获取方法信息。
在这里插入图片描述
通过上面的代码可以直接获取到String类的方法信息,运行结果如下,由于String类方法太多,只展示部分方法。
在这里插入图片描述

2.4、数组类的加载

创建数组类的情况稍微有些特殊,数组类由JVM在运行时根据需要直接创建,所以数组类没有对应的class文件,也就没有二进制形式,所以也就无法使用类加载器去创建数组类。但数组的元素类型仍然需要依靠类加载器去创建。创建数组类的过程如下:

  • (1)如果数组的元素类型是引用类型,那么就遵循定义的加载过程递归加载和创建数组的元素类型,JVM使用指定的元素类型和数组维度来创建新的数组类。
  • (2)如果数组的元素是基本数据类型,比如int类型的数组,由于基本数据类型是由JVM预先定义的,所以也不需要类加载,只需要关注数组维度即可。

如果数组的元素类型是引用类型,数组类的可访问性就由元素类型的可访问性决定。否则数组类的可访问性将被缺省定义为public。

3、链接(Linking)阶段

3.1、链接阶段之验证(Verification)

类加载到机器内存后,就开始链接操作,验证是链接操作的第一步。验证的目的是保证加载的字节码是合法、合理并符合规范的。验证的步骤比较复杂,实际要验证的项目也很繁多,如下图所示:
在这里插入图片描述
验证的内容涵盖了类数据信息的格式检查、语义检查、字节码验证、符号引用验证,其中格式检查会和加载阶段一起执行。验证通过之后,类加载器才会成功将类的二进制数据信息加载到方法区中。格式检查之外的验证操作将会在方法区中进行。如果不在链接阶段进行验证,那么class文件运行时依旧需要进行各种检查,虽然链接阶段的验证拖慢了加载速度,但是却提高了程序执行的速度,正所谓“磨刀不误砍柴工”。

3.1.1、格式检查

主要检查是否以魔数OxCAFEBABE开头,主版本和副版本号是否在当前JVM的支持范围内,数据中每一个项是否都拥有正确的长度等。

3.1.2、字节码的语义检查

JVM会进行字节码的语义检查,但凡在语义上不符合规范的,JVM也不会验证通过,比如JVM会检查下面4项语义是否符合规范:

  • (1)是否所有的类都有父类的存在(Object除外)。
  • (2)是否一些被定义为final的方法或者类被重写或继承了。
  • (3)非抽象类是否实现了所有抽象方法或者接口方法。
  • (4)是否存在不兼容的方法,比如方法的签名除了返回值不同,其他都一样。

3.1.3、字节码验证

JVM还会进行字节码验证,字节码验证也是验证过程中最为复杂的一个过程。它试图通过对字节码流的分析,判断字节码是否可以被正确地执行,比如JVM会验证字节码中的以下内容。

  • (1)在字节码的执行过程中,是否会跳转到一条不存在的指令。
  • (2)函数的调用是否传递了正确类型的参数。
  • (3)变量的赋值是不是给了正确的数据类型等。
  • (4)检查栈映射帧的局部变量表和操作数栈是否有着正确的数据类型。

遗憾的是,百分之百准确地判断一段字节码是否可以被安全执行是无法实现的,因此,该过程只是尽可能地检查出可以预知的明显的问题。如果在这个阶段无法通过检查,JVM也不会正确装载这个类。但是,如果通过了这个阶段的检查,也不能说明这个类是完全没有问题的。在前面3次检查中,已经排除了文件格式错误、语义错误以及字节码的不正确性。但是依然不能确保类是没有问题的。

3.1.4、符号引用验证

class文件中的常量池会通过字符串记录将要使用的其他类或者方法。因此,在验证阶段,JVM就会检查这些类或者方法是否存在,检查当前类是否有权限访问这些数据,如果一个需要使用的类无法在系统中找到,则会抛出“NoClassDefFoundError”错误,如果一个方法无法被找到,则会抛出“NoSuchMethodError”错误。注意,这个过程发生在链接阶段的解析环节。

3.2、链接阶段之准备(Preparation)

当一个类验证通过时,JVM就会进入准备阶段。准备阶段主要负责为类的静态变量分配内存,并将其初始化为默认值。JVM为各类型变量默认的初始值如下表所示:
在这里插入图片描述
Java并不直接支持boolean类型,对于boolean类型,内部实现是int,int的默认值是0,对应的boolean类型的默认值是false。

注意,这个阶段不会为使用static final修饰的基本数据类型初始化为0,因为final在编译的时候就会分配了,准备阶段会显式赋值。也不会为实例变量分配初始化,因为实例变量会随着对象一起分配到Java堆中。这个阶段并不会像初始化阶段那样会有初始化或者代码被执行。代码清单如下展示了static final修饰的基本数据类型不会被初始化为0。
在这里插入图片描述
查看该类的字节码字段属性,如下图所示:
在这里插入图片描述
如果类字段的字段属性表中存在ConstantValue属性,那么在准备阶段该类字段value就会被显式赋值,也就是说在准备阶段,num的值是1,而不是0。仅被static修饰的类变量,在准备阶段初始化为默认值。

3.3、链接阶段之解析(Resolution)

在准备阶段完成后,类加载进入解析阶段。解析阶段主要负责将类、接口、字段和方法的符号引用转为直接引用。

符号引用就是一些字面量的引用,和JVM的内部数据结构及内存布局无关。比如class文件中,常量池存储了大量的符号引用。在程序实际运行时,只有符号引用是不够的,比如当println()方法被调用时,系统需要明确知道该方法的位置。

以方法为例,JVM为每个类都准备了一张方法表,将其所有的方法都列在表中,当需要调用一个类的方法的时候,只要知道这个方法在方法表中的偏移量就可以直接调用该方法。通过解析操作,符号引用就可以转变为目标方法在类中方法表中的位置,从而使得方法被成功调用。代码清单如下演示了方法在解析阶段的调用过程。
在这里插入图片描述
其对应的字节码如下:

     0 getstatic #2 <java/lang/System.out>
     3 ldc #3 <atguigu>
     5 invokevirtual #4 <java/io/PrintStream.println>
     8 return

invokevirtual #4 <java/io/PrintStream.println>方法的符号引用指向常量池中第四个选项,如下图所示:
在这里插入图片描述
方法调用的常量是类中方法的符号引用,包含类名和方法以及方法参数,解析阶段就是获取这些属性在内存中的地址,具体过程如下图所示:
在这里插入图片描述

通过第4项常量找到第21项类名常量和第22项方法的名称描述符即可。

4、初始化(Initialization)阶段

类的初始化是类装载的最后一个阶段。如果前面的步骤都没有问题,那么表示类可以顺利装载到系统中,然后JVM才会开始执行Java字节码,也就是说到了初始化阶段,JVM才真正开始执行类中定义的Java程序代码。初始化阶段的重要工作是执行类的()方法(即类初始化方法),该方法仅能由Java编译器生成并被JVM调用,程序开发者无法自定义一个同名的方法,也无法直接在Java程序中调用该方法。()方法是由类静态成员的赋值语句以及static语句块合并产生的。通常在加载一个类之前,JVM总是会试图加载该类的父类,因此父类的()方法总是在子类()方法之前被调用,也就是说,父类的static语句块优先级高于子类,简要概括为由父及子,静态先行。

Java编译器并不会为所有的类都产生()方法。以下情况class文件中将不会包含()方法:

  • (1)一个类中并没有声明任何的类变量,也没有静态代码块时。
  • (2)一个类中声明类变量,但是没有明确使用类变量的初始化语句以及静态代码块来执行初始化操作时。
  • (3)一个类中包含static final修饰的基本数据类型的字段,这些类字段初始化语句采用编译时常量表达式。

代码清单如下展示了哪些情况不会产生()方法:
在这里插入图片描述
查看该类对应的方法信息,如下图所示,可以看到不存在()方法。
在这里插入图片描述

4.1、static与final搭配

static与final定义的变量在准备阶段完成赋值,但是并不是所有的变量都在链接阶段的准备阶段完成赋值,下面通过代码案例说明不同情况下的不同阶段赋值,如代码清单如下所示:
在这里插入图片描述
对应字节码指令在()方法中:
在这里插入图片描述
从字节码指令中看到只有定义类成员变量a、INTEGER_CONSTANT1、INTEGER_CONSTANT2和s1时是在初始化阶段的()方法中完成。那么另外两个类变量是怎么赋值的呢?通过jclasslib查看字段属性表,如下图所示,可以看到只有INT_CONSTANT和helloworld0两个常量拥有ConstantValue,说明INT_CONSTANT = 10和String s0="helloworld0"是在链接阶段的准备阶段完成的。
在这里插入图片描述
我们得出的结论就是,基本数据类型和String类型使用static和final修饰,并且显式赋值中不涉及方法或构造器调用,其初始化是在链接阶段的准备环节进行,其他情况都是在初始化阶段进行赋值。

4.2、()方法的线程安全性

对于()方法的调用,JVM会在内部确保其多线程环境中的安全性。JVM会保证一个类的()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的()方法,其他线程都需要阻塞等待,直到活动线程执行()方法完毕。正是因为方法()带锁线程安全的,如果在一个类的()方法中有耗时很长的操作,就可能造成多个线程阻塞,导致死锁,这种死锁是很难发现的,因为并没有可用的锁信息。如果之前的线程成功加载了类,则等在队列中的线程就没有机会再执行()方法了,当需要使用这个类时,JVM会直接返回给它已经准备好的信息。

4.3、类的初始化时机:主动使用和被动使用

初始化阶段是执行类构造器()方法的过程。虽然有些类已经存在()方法,但是并不确定什么时候会触发执行,可以触发()方法的情景称为主动使用,不能触发()方法执行的情景称为被动使用。主动使用可以触发类的初始化,被动使用不能触发类的初始化。

4.3.1、主动使用

JVM不会无条件地装载class文件,class文件只有在首次使用的时候才会被装载。JVM规定,一个类或接口在初次使用前,必须要进行初始化。这里的“使用”是指主动使用,主动使用包含下列几种情况。

(1)创建一个类的实例时,比如使用new关键字、反射、克隆或反序列化等方式创建实例。首先创建Order类,Order类中写了一段静态代码块,如下代码清单所示:
在这里插入图片描述
一个类被初始化的标志就是执行()方法,查看Order类的()方法,如下图所示,说明只要执行了静态代码块就表示执行了()方法,即Order类被初始化。
在这里插入图片描述
代码清单如下演示了new[test()方法]关键字创建实例、反序列化[test2()方法],以及反射[test3()方法]都会调用类的初始化,代码中如果输出了Order类中对应的输出语句即表示执行了类的初始化。注意,案例中序列化[test1()方法]的作用仅仅是将对象序列化为order.dat文件,为反序列化[test2()方法]做铺垫,虽然序列化[test1()方法]也输出了Order类中的语句,这是因为new关键字调用了类的初始化,而不是序列化调用了类的初始化。
在这里插入图片描述
test()、test2()、test3()方法的执行结果如下,表明使用new关键字、反序列化、反射等方式都会执行类的初始化。

     Order类的初始化过程

(2)调用类的静态方法时,即当使用了字节码invokestatic指令时。

Order类中添加静态方法,如下所示:

     public static void method(){
         System.out.println("Order method()....");
     }

ActiveUse1类中添加test4()方法用于调用类的静态方法,如下所示:
在这里插入图片描述
test4()方法执行结果如下,可以发现调用类的静态方法的时候也执行了类的初始化:

     Order类的初始化过程
     Order method()....

(3)使用类、接口的静态字段时(final修饰特殊考虑),字节码指令中使用了getstatic或者putstatic指令。

在Order类中添加以下属性:

     public static int num1 = 1;
     public static final int num2 = 2;
     public static final int num3 = new Random().nextInt(10);

创建ActiveUse2类用于测试使用类的静态字段是否会触发类的初始化,如代码清单如下所示:
在这里插入图片描述
test1()方法的执行结果如下所示:

     Order类的初始化过程
     test1()方法执行结果:1

test2()方法的执行结果如下所示:

     test2()方法执行结果:2

test3()方法的执行结果如下所示:

     Order类的初始化过程
     test3()方法执行结果:8

从结果来看,当字段使用static修饰且没有使用final字段修饰时,如果使用该字段会触发类的初始化;当static和final同时修饰字段时,且该字段是一个固定值则不会触发类的初始化,因为该类型的字段在链接过程的准备阶段就已经被初始化赋值了,不需要类初始化以后才能使用,所以不会执行类的初始化;num3是因为在程序执行之前无法确定具体的数值,所以需要执行类的初始化以后才能继续执行。

上面讲述了类的静态字段是否触发类的初始化,接下来再测试接口的静态字段是否会触发接口的初始化,创建CompareA接口如代码清单所示:
在这里插入图片描述
查看CompareA中()方法,如下图所示,可以看到如果创建了线程对象t并且里面的代码块语句输出则表示执行了()方法。
在这里插入图片描述
在ActiveUse2类中添加test4()和test5()方法用于测试接口的静态属性是否会触发类的初始化:
在这里插入图片描述
test4()方法执行结果如下:

     test4()方法执行结果:1

test5()方法执行结果如下:

     CompareA的初始化
     test5()方法执行结果:3

可以看到接口的静态字段和类的静态字段对类的初始化效果是一样的,需要注意的是接口的字段默认是由static final修饰的,接口中没有字段是被static单独修饰的。

(4)初始化子类时,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。JVM虚拟机初始化一个类时,要求它的所有父类都已经被初始化,但是这条规则并不适用于接口。在初始化一个类时,并不会先初始化它所实现的接口;在初始化一个接口时,并不会先初始化它的父接口。因此,一个父接口并不会因为它的子接口或者实现类的初始化而初始化。只有当程序首次使用特定接口的静态字段时,才会导致该接口的初始化。

4.3.2、被动使用

除了以上的情况属于主动使用,其他的情况均属于被动使用。被动使用不会引起类的初始化。也就是说并不是在代码中出现的类,就一定会被加载或者初始化。如果不符合主动使用的条件,类就不会初始化。被动使用包含如以下几种情况:

  • (1)当访问一个静态字段时,只有真正声明这个字段的类才会被初始化。当通过子类引用父类的静态变量,不会导致子类初始化。
  • (2)通过数组定义类引用,不会触发此类的初始化。
  • (3)引用常量不会触发此类或接口的初始化,因为常量在链接阶段已经被显式赋值,主动使用第3条规则我们已经讲过了,不再赘述。
  • (4)调用ClassLoader类的loadClass()方法加载一个类,并不是对类的主动使用,不会导致类的初始化。

5、类的使用(Using)

任何一个类在使用之前都必须经历过完整的加载、链接和初始化3个步骤。一旦一个类成功经历这3个步骤之后,便“万事俱备,只欠东风”,就等着开发者使用了。开发人员可以在程序中访问和调用它的静态类成员信息(比如静态字段、静态方法等),或者使用new关键字创建对象实例。

6、类的卸载(Unloading)

和前面讲过对象的生命周期类似,对象在使用完以后会被垃圾收集器回收,那么对应的类在使用完成以后,也有可能被卸载掉。在了解类的卸载之前,需要先厘清类、类的加载器、类的Class对象和类的实例之间的引用关系。

6.1、类、类的加载器、类的Class对象、类的实例之间的引用关系

(1)类加载器和类的Class对象之间的关系:在类加载器的内部实现中,用一个Java集合来存放所加载类的引用。另外,一个Class对象总是会引用它的类加载器,调用Class对象的getClassLoader()方法,就能获得它的类加载器。由此可见,代表某个类的Class对象与该类的类加载器之间为双向关联关系。

(2)类、类的Class对象、类的实例对象之间的关系:一个类的实例总是引用代表这个类的Class对象。Object类中定义了getClass()方法,这个方法返回代表实例所属类的Class对象的引用。此外,所有的Java类都有一个静态属性class,它引用代表这个类的Class对象。

6.2、类的生命周期

当类被加载、链接和初始化后,它的生命周期就开始了。当代表类的Class对象不再被引用,即不可触及时,Class对象就会结束生命周期,类在方法区内的数据也会被卸载,从而结束类的生命周期。一个类何时结束生命周期,取决于代表它的Class对象何时结束生命周期。

6.3、案例

自定义一个类加载器MyClassLoader加载自定义类Order,那么就可以通过Order的Class对象获取到对应的类加载器,再通过Order类的实例对象获取到类Class对象,如下代码清单所示:
在这里插入图片描述
类、类的加载器、类的Class对象、类的实例之间的引用关系如下图所示:
在这里插入图片描述
myLoader变量和order变量间接引用代表Order类的Class对象,而orderClass变量则直接引用代表Order类的Class对象。如果程序运行过程中,将上图左侧三个引用变量都置为null,此时Order对象结束生命周期,myLoader对象结束生命周期,代表Order类的Class对象也结束生命周期,Order类在方法区内的二进制数据被卸载。当再次有需要时,会检查Order类的Class对象是否存在,如果存在会直接使用,不再重新加载;如果不存在Order类会被重新加载,在JVM的堆区会生成一个新的代表Order类的Class实例。

6.4、类的卸载

通过上面的案例可以知道当类对象没有引用时,可能会产生类的卸载,类的卸载需要满足如下三个条件:

  • (1)该类所有的实例已经被回收。
  • (2)加载该类的类加载器的实例已经被回收。
  • (3)该类对应的Class对象没有任何对方被引用。

但是需要注意,并不是所有类加载器下面的类都可以被卸载,Java自带的三种类加载器的实例是不可以被卸载的,所以它们加载的类在整个运行期间是不可以被卸载的,只有被开发者自定义的类加载器实例加载的类才有可能被卸载。一个已经加载的类被卸载的概率很小,至少被卸载的时间是不确定的。开发者在开发代码的时候,不应该对虚拟机的类卸载做任何假设,在此前提下,再来实现系统中的特定功能。

6.5、回顾:方法区的垃圾回收

方法区的垃圾收集主要回收两部分内容,分别是常量池中废弃的常量和不再使用的类。HotSpot虚拟机对常量池的回收策略是很明确的,只要常量池中的常量没有被任何地方引用,就可以被回收。

JVM判定一个常量是否“废弃”还相对简单,而要判定一个类是否属于“不再被使用的类”的条件就比较苛刻了,需要同时满足下面三个条件:

  • (1)该类所有的实例都已经被回收。也就是Java堆中不存在该类及其任何派生子类的实例。
  • (2)加载该类的类加载器已经被回收。这个条件除非是经过精心设计的可替换类加载器的场景,如OSGi、JSP的重加载等,否则通常是很难达成的。
  • (3)该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

上述三个条件并不是JVM卸载无用类的必要条件,JVM可以卸载类也可以不卸载类,不会像对象那样没有引用就肯定回收。

7、小结

主要介绍了JVM将class文件加载到内存所经历的过程,这个过程可分为加载、链接和初始化三大步骤。加载阶段主要负责根据类的二进制数据创建类模板对象。链接阶段主要负责获取类或接口并将其组合到JVM的运行时状态,链接又分为验证、准备和解析三个阶段。初始化主要负责为静态字段赋值,以及执行()方法,注意类的初始化仅会被执行一次。学习类的加载过程可以帮助我们更加透彻地理解class文件的执行过程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1581628.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PVE下安装配置openwrt和ikuai

开端 openwrt 和 ikuai 是比较出名的软路由系统。我最早接触软路由还是因为我的一个学长要改自己家里的网络&#xff0c;使用软路由去控制网络。我听说后便来了兴致&#xff0c;也在我家搞了一套软路由系统。现在我已经做完了&#xff0c;就想着写个文章记录一下。 软路由简介…

GFS部署实验

目录 1、部署环境 ​编辑 2、更改节点名称 3、准备环境 4、磁盘分区&#xff0c;并挂载 5. 做主机映射--/etc/hosts/ 6. 复制脚本文件 7. 执行脚本完成分区 8. 安装客户端软件 1. 安装解压源包 2. 创建gfs 3. 安装 gfs 4. 开启服务 9、 添加节点到存储信任池中 1…

应急响应-拒绝服务钓鱼指南DDOS压力测试邮件反制分析应用日志

知识点 1、CC攻击分析 2、钓鱼邮件分析 3、内网渗透分析 一、演示案例-内网应急-日志分析-爆破 MSSQL-1433 SMB-445 二、演示案例-红队APT-钓鱼邮件-内容&发信人&附件 如何分析邮件安全性&#xff1a; 1、看发信人地址 2、看发信内容信息 3、看发信内容附件 看后…

2011年认证杯SPSSPRO杯数学建模B题(第一阶段)生物多样性的评估全过程文档及程序

2011年认证杯SPSSPRO杯数学建模 B题 生物多样性的评估 原题再现&#xff1a; 2010 年是联合国大会确定的国际生物多样性年。保护地球上的生物多样性已经越来越被人类社会所关注&#xff0c;相关的大规模科研和考察计划也层出不穷。为了更好地建立国际交流与专家间的合作&…

UML2.0在系统设计中的实际使用情况

目前我在系统分析设计过程中主要使用UML2.0来表达&#xff0c;使用StarUML软件做实际设计&#xff0c;操作起来基本很顺手&#xff0c;下面整理一下自己的使用情况。 1. UML2.0之十三张图 UML2.0一共13张图&#xff0c;可以分为两大类&#xff1a;结构图-静态图&#xff0c;行…

学习Rust的第一天:基础知识

Introduction 介绍 I am Shafin Murani is a software development student and I am documenting every single day of my progress in learning rust. This is the first article of the series. Shafin Muranishi 是一名软件开发专业的学生&#xff0c;这是他在30天内记录学…

苹果电脑(Mac)怎么清理 itunes 备份?

苹果电脑用户广泛利用 iTunes 应用程序对 iPhone 或 iPad进行定期备份&#xff0c;以确保珍贵的数据安全无虞。然而&#xff0c;随着备份历史的增长&#xff0c;它们会在磁盘上积累大量空间&#xff0c;尤其当您频繁为多台设备备份时&#xff0c;存储资源可能会迅速消耗殆尽。为…

Docker部署Logstash同步Mysql数据到ES

1、准备配置文件文件夹 2、部署logstash & elasticsearch docker pull docker.elastic.co/logstash/logstash:7.15.0 ## 替换{你的ES地址}为ES地址 docker run -d --name logstash -p 5044:5044 -p 9600:9600 -v D:\logstash\data\:/usr/share/logstash/data -v D:\logst…

服务器数据恢复—V7000存储raid5数据恢复案例

服务器数据恢复环境&#xff1a; P740AIXSybaseV7000存储阵列柜&#xff0c;阵列柜上有12块SAS机械硬盘&#xff08;包括1块热备盘&#xff09;。 服务器故障&#xff1a; 管理员在日常巡检过程中发现阵列柜中有一块磁盘发生故障&#xff0c;于是更换磁盘并同步数据&#xff0…

Kafka基础/1

Kafka 概念 Kafka 是一个分布式的流媒体平台。 应用&#xff1a;消息系统、日志收集、用户行为追踪、流式处理 特点&#xff1a;高吞吐量、消息持久化、高可靠性、高扩展性 术语&#xff1a; broker&#xff1a;Kafka 的服务器&#xff0c;Kafka 当中每一台服务器&#xf…

Visual Studio Code 终端为管理员权限

第一部 1、 Visual Studio Code 快捷方式启动选项加上管理员启动 第二步 管理员方式运行 powershell Windows 10的任务栏自带了搜索。或者开始菜单选搜索只需在搜索框中输入powershell。 在出来的搜索结果中右击Windows PowerShell&#xff0c;然后选择以管理员方式运行。 执…

《前端面试题》- JS基础 - call()、apply()、bind() 的区别

call 、bind 、 apply 这三个函数的功能都是改变this的指向问题&#xff0c;但是也存在一定的区别。 call 的参数是直接放进去的&#xff0c;第二第三第 n 个参数全都用逗号分隔,apply 的所有参数都必须放在一个数组里面传进去bind 除了返回是函数以外&#xff0c;它 的参数和…

Training - 使用 WandB 配置 可视化 模型训练参数

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://blog.csdn.net/caroline_wendy/article/details/137529140 WandB (Weights&Biases) 是轻量级的在线模型训练可视化工具&#xff0c;类似于 TensorBoard&#xff0c;可以帮助用户跟踪…

js语法---简单理解promise

promise语法结构 创建一个promise对象 let p new Promise(function(resolve,reject){// 执行的操作...// 判断操作的结果并执行对应的回调函数if(){resolve()}else{reject()} } 以上实例化了一个promise对象&#xff0c;其中包含了一个参数function&#xff0c;这个函数会在…

【配电网故障定位】基于二进制粒子群算法的配电网故障定位 12节点配电系统故障定位【Matlab代码#76】

文章目录 【获取资源请见文章第5节&#xff1a;资源获取】1. 配电网故障定位2. 二进制粒子群算法3. 部分代码展示4. 仿真结果展示5. 资源获取 【获取资源请见文章第5节&#xff1a;资源获取】 1. 配电网故障定位 配电系统故障定位&#xff0c;即在配电网络发生故障的时候&…

了解Vue中的 computed 计算属性

目录 1. computed计算属性介绍和基础语法 1.1. 概念 1.2. 语法 2. “计算属性”和“方法”的对比 2.1. computed 计算属性 2.1.1. 作用 2.1.2. 语法 2.2. methods 方法 2.2.1. 作用 2.2.2. 语法 2.2.3. 缓存特性&#xff08;提升性能&#xff09; 3. computed 计算…

ssm“最多跑一次”微信小程序

采用技术 ssm“最多跑一次”微信小程序的设计与实现~ 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringMVCMyBatis 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统实现的功能 本次设计任务是要设计一个“最多跑一次”微信小程序&#xff0c;…

AI大模型日报#0409:Llama 3下周发布、特斯联20亿融资、Karpathy新项目

导读&#xff1a; 欢迎阅读《AI大模型日报》&#xff0c;内容基于Python爬虫和LLM自动生成。目前采用“文心一言”生成了每条资讯的摘要。标题: 120亿Stable LM 2上线即开源&#xff01;2万亿token训练&#xff0c;碾压Llama 2 70B 摘要: Stable LM 2 12B参数版本发布&#x…

OpenMesh 计算网格顶点Voronoi面积

文章目录 一、简介二、实现代码三、实现代码参考资料一、简介 在计算离散的微分算子时(如拉普拉斯算子、高斯曲率等),总是会需要计算某个网格顶点的局部面积,主要有以下几种: 该操作类似于点云中的邻域操作,只不过点云的邻域一般是基于一个圆或者一个圆柱,而这里则是某个…

VSCode+Cmake 调试时向目标传递参数

我有一个遍历文件层次结构的程序&#xff0c;程序根据传入的文件路径&#xff0c;对该路径下的所有文件进行遍历。这个程序生成一个名为 ftw 的可执行文件&#xff0c;如果我要遍历 /bin 目录&#xff0c;用法为&#xff1a; ftw /bin问题是&#xff0c;如果我想单步跟踪&…