JVM 类加载器
字节码的结构
魔数u4 cafe babe
版本u4 52 = java8
常量池计数器u2 从1开始,0索引留给不需要的情况
常量池 表 #1 -> #计数器-1
类标识符 u2 public final abstrat class annotion interface 之类
类索引u2 名字
父类索引u2 父类名字
接口计数器 u2 接口数组长度
接口集合 表 接口索引数组
字段计数器 u2
字段 表
-访问标识符 u2
-字段名索引 u2
-字段描述符索引 u2
-字段属性计数器 u2
-字段属性 表
方法计数器 u2
方法 表
-访问标识符 u2
-方法名索引 u2
-方法描述符索引 u2
-方法属性计数器 u2
-方法属性 表
前段编译器
将高级语言源文件编译成Class文件的过程就是前端编译的过程。这是java跨平台执行的关键。
前段编译器只负责将高级语言,编译成字节码,不负责具体的性能优化之类的,这些要在执行引擎中的JIT及时编译器中负责。
前段编译器编译的流程如下。
词法分析
检查关键字,引用等等有没有错误。
语法分析
根据具体的高级语言的语法分析,是否出现语法错误。
语义分析
根据逻辑关系,分析是否有可能出现的逻辑问题。比如未初始化啊,数组越界之类的。这部分的功能有限,只能发现较为明显的逻辑错误。
生成字节码
类加载过程
字节码文件并不存放在内存中,而是在内存外(可能是在磁盘中,也可能在网络中,也可能是动态生成的)。当需要用到的时候再由类加载去寻找并载入内存到运行时数据区才可以被JVM使用。
类加载的过程有7个阶段。
加载——验证——准备——解析——初始化——使用——卸载
加载
1 通过某种方式找到对应的Class文件,获取到二进制数据流。
2 解析二进制数据流,并根据来建立对应方法区中的数据结构。
3 创建java.lang.Class类对象实例,用来作为方法区访问类数据的入口。(也就是给一个索引到方法区数据结构的对象)
Class类的构造方法是私有的,只有JVM可以创建。然后这个Class实例对象,是元空间的入口,也是实现反射的关键数据。通过Class类提供的接口方法,可以获得这个描述类的种种信息。
验证
属于链接中的第一步。
加载到内存之后,我们就可以快速的对字节码进行验证,保证字节码是合法,合规合理的。
字节码格式验证,字节码语义验证,字节码验证(逻辑),符号引用验证。
这和前端编译器,编译流程很像,词法分析对应格式验证,语法分析对应语义验证,语义分析对应字节码验证,以及符号引用验证。
准备阶段
这个时候,字节码通过验证了,那么可以开始完善类的静态部分了,这样一个Class对象算是可用。
也就是静态的成员变量,分配内存,初始化值。
1 分配内存,并进行初始化内存。
对于类的静态成员变量,都会先对内存空间初始化一个值,根据类型不同,初始化的也不同。
java不支持boolean原生类型,内部实现实际上是通过int实现。默认int 0对应false。
这个初始化默认值对于static final修饰的基本数据类型无用,所以没有,因为其不需要多这么个初始为默认值的步骤,而可以直接确定最终值,在准备阶段直接进行显式赋值。(另外对于String类型在显式赋值中不涉及方法或构造器调用,其初始化是在链接阶段的准备环节进行)
对于实例变量,在准备阶段不会进行初始化,因为实例变量会随着实例对象分配到堆中,你不能提前知道要创建实例对象了并提前给创建好。
(仅仅是初始化内存空间,相当于清理垃圾,并不会执行任何代码来赋值,这一步是后面初始化阶段做的事情)
解析阶段
将符号引用,转换为实际的直接引用。在实际的运行环境中,寻找符号引用的直接引用,替换到类对象中。
这个阶段有可能在初始化之后再进行,不确定。
初始化阶段
这是类装载的最后一个阶段。这个阶段,JVM才会执行初始化代码,根据类的初始化代码进行初始化类对象。
最重要的工作就是执行<cinit>()方法。(类的初始化方法),这个方法只能由java编译器生成,并只能被JVM调用(我们无法调用)。
<cinit>()是根据类的静态成员赋值语句以及static代码块合并形成的。但是需要记住,在加载子类之前,JVM总会试图先加载其父类,所以父类的《cinit》一定先于子类的《cinit》执行。
如果没有静态赋值语句和静态代码块,那么编译器就不会产生《cinit》方法
cinit()方法只能在类加载的时候被调用一次,后续不能再调用,所以当JVM内部多个线程同时加载一个类的时候就需要保证线程安全,cinit方法自带同步锁,只有一个线程能执行cinit,其他线程都阻塞。等待执行完毕后会通知其他线程返回这个结果。
如果cinit中出现耗时长操作,会导致线程阻塞,难以排查。
初始化时机(cinit调用时机)
因为要执行代码,所以无疑初始化需要时间开销。所以并不是任何时候都能随时进行初始化的。初始化的时机就变得非常重要。
有两种使用类的方式,主动使用会导致初始化发生,被动使用不需要初始化。
1 主动使用(核心就是涉及用到Class对象)
也就是当我们需要用到类的静态变量了,那么一定会进行初始化。
-
new实例对象,或者反序列化得到实例对象
-
反射获取到Class对象
-
调用静态方法,静态方法可能涉及到静态变量的访问,所以可能静态成员变量需要初始化。
-
访问未被初始化阶段赋值的静态成员变量(如果访问static final修饰的在准备阶段就赋值的静态变量,那不需要初始化就可以,但是是static final String NAME = new String(”123:“)这种就不可以)
对于接口来说,所有的静态字段都是static final修饰的,效果和类一样。
初始化子类时,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。JVM虚拟机初始化一个类时,要求它的所有父类都已经被初始化,但是这条规则并不适用于接口。在初始化一个类时,并不会先初始化它所实现的接口;在初始化一个接口时,并不会先初始化它的父接口。因此,一个父接口并不会因为它的子接口或者实现类的初始化而初始化。只有当程序首次使用特定接口的静态字段时,才会导致该接口的初始化
-
如果一个接口定义了default方法,那么直接实现或者间接实现该接口的类在初始化之前需要实现接口的初始化
-
JVM启动时,用户需要指定一个要执行的主类[包含main()方法的那个类],JVM会先初始化这个主类。这个类在调用main()方法之前被链接和初始化,main()方法的执行将依次加载,链接和初始化后面需要使用到的类。
-
初次创建MethodHandle实例时,初始化该MethodHandle实例时指向的方法所在的类
2 被动使用
并不是在代码中出现的类,就一定会被加载或者初始化
-
当访问一个静态字段时,只有真正声明这个字段的类才会被初始化。当通过子类引用父类的静态变量,不会导致子类初始化,而如果访问子类的,就会导致父类进行初始化,以及子类的初始化
-
通过数组定义类引用,不会触发此类的初始化。直到给具体的数组中的元素赋予对象才会。数组定义的引用,只是从编译阶段确定,所以并不会导致初始化。
-
引用常量不会触发此类或接口的初始化,因为常量在链接阶段已经被显式赋值
-
调用ClassLoader类的loadClass()方法加载一个类,并不是对类的主动使用,不会导致类的初始化。通过反射获取到Class对象,才会导致初始化,例如Class.forName()会导致初始化。
类的卸载
类的卸载,涉及到类加载,类Class对象,类实例之间的引用关系。
类加载器和加载的类对象,相互关联。类加载内部Java集合存放了加载过的类对象引用,而类对象也引用加载他的类加载器。
类实例总是引用代表这个类的Class对象getClass(),类中都有一个静态属性class(通过类名.class可获得),引用着这个类的Class对象。
所以条条大路通Class对象。
所以什么时候卸载类,要等到Class对象不在被引用的时候。
所以类被卸载的三个条件,都是围绕Class对象被引用
-
所有类的实例对象都被回收
-
Class对象没有直接被引用
-
类的加载器被GC回收(只有用户自定义加载器能够被回收)
这样图中Order.class实例的三个方向的引用都断了,那么可以卸载类了。
类加载器
实际上属于类加载过程的细节。类加载过程中第一个加载阶段就是类加载器负责的。
类加载器在整个装载阶段,只能影响到类的加载,而无法改变类的链接和初始化行为(存疑)
类加载器必要性
了解类加载器机制,可以解决以下问题。
(1)避免在开发中遇到java.lang.ClassNotFoundException异常或java.lang.NoClassDefFoundError异常时手足无措。
(2)只有了解类加载器的加载机制,才能够在出现异常的时候快速地根据错误异常日志定位并解决问题。
(3)需要支持类的动态加载或需要对编译后的class文件进行加解密操作时,就需要与类加载器打交道。
(4)开发人员可以在程序中编写自定义类加载器来重新定义类的加载规则,以便实现一些自定义的处理逻辑
也就是异常处理,动态或者自定义加载
类加载器的命名空间
每一个类是通过加载它的类加载器加上类本身的名字来确定其在JVM中的唯一性!而不仅仅是通过类的名字。
每个类加载器都有自己的命名空间,命名空间由该类加载器(实例)及所有的父类加载器组成,在同一命名空间中,不会出现类的完整名字(包括类的包名)相同的两个类;
这样就保证了类的唯一性。
在不同的命名空间中,有可能会出现类的完整名字(包括类的包名)相同的两个类;在大型应用中,我们往往借助这一特性,来运行同一个类的不同版本。
也就是通过不同的类加载器,加载一个类的不同版本。
类加载的基本特征
通常有三大特征:双亲委派,可见性,单一性
双亲委派实际上就是优先交给上一级加载器加载。这样是为了避免类在其他地方重复加载,第二个是恶意代码不能通过重复加载来替换核心类库。
可见性是下级加载器,可以访问上级加载器加载了哪些类型,反过来是不行的。也就是说高级加载器加载的类,只能看到自己和更高级的类的存在,如果和同级或者下级类进行交互,是ClassNotFound的。而下级加载器加载的类就可以看到上级加载器加载的类的存在。(就像是父类和子类的关系一样,但是只能是访问关系一样)
单一性,因为父加载器加载过的类型对于子加载器是可见的,所以父加载器加载的类型就不会在子加载器中重复加载。但是在同一级的加载器中(兄弟加载器)相互是不可见的,所以同一个类可以被同级别的加载器加载多次。
类加载器的分类
实际上就是类加载器分级,是根据什么分级的,不同级别的类加载器有什么职责。
从最本质的来分,JVM有两种类加载器,启动类加载器和自定义类加载器。
自定义类加载器通常是指由开发人员自定义的一类类加载器,但是Java虚拟机规范中规定的更为广泛,凡是从抽象类ClassLoader派生而来的类加载器都是自定义类加载器。那么不是从ClassLoader派生而来的类加载器自然就是启动类加载器了。
无论类加载器的类型如何划分,在程序中我们最常见的类加载器结构如图20-1所示,其中扩展类加载器和应用程序类由抽象类ClassLoader派生而来
实际上不同加载器之间是聚合关系,也就是下级加载器,有上级加载器的引用。而不是继承关系。
只是在ClassLoader这个抽象类中,有一个成员变量引用上一级的加载器,叫做parent。所以上级加载器才被叫做父加载器。
引导类加载器(启动类加载器)
这两种称呼,一种是基于职责负责引导程序运行,一种是指是启动程序的类加载器。
引导类加载器(BootstrapClassLoader,又称启动类加载器)使用C/C++语言实现,嵌套在JVM内部。
引导类加载器不继承java.lang.ClassLoader,没有父类加载器。出于安全考虑,引导类加载器主要用来加载Java的核心库,也就是“JAVA_HOME/jre/lib/rt.jar”或“sun.boot.class.path”路径下的内容,指定为扩展类和应用程序类加载器的父类加载器。
所以引导类加载器作用有限,主要用来加载核心类库。
扩展类加载器
扩展类加载器(ExtensionClassLoader)由Java语言编写,间接继承与ClassLoader
扩展类加载器主要负责从java.ext.dirs系统属性所指定的目录或者JDK的安装目录的jre/lib/ext子目录下加载类库。如果用户创建的类放在上述目录下,也会自动由扩展类加载器加载。简言之扩展类加载器主要负责加载Java的扩展库。
应用程序类加载器
也叫做系统加载器,也是由Java语言编写,间接继承于ClassLoader类父类加载器为扩展类加载器。
负责加载环境变量classpath或系统属性java.class.path指定路径下的类库,应用程序中的类加载器默认是应用程序类加载器。(在IDE中,可以查看到JDK的CLASSPATH。在命令行执行的时候CLASSPATH就是当前路径)
它是用户自定义类加载器的默认父类加载器,通过ClassLoader的getSystemClassLoader()方法可以获取到该类加载器。
自定义加载器
自定义加载器有很多好处。
-
实现插件效果,即插即用。通过启用自定义加载器,加载额外功能。不需要的时候直接回收自定义加载器,就拔除功能。
-
隔离加载类。同级类加载器之间相互隔离。所以我们可以通过将不同的类簇通过不同的同级类加载器加载实现隔离。
-
修改类加载方式,除了启动类加载器之外,其他的类加载器并非一定引入。所以我们可以改变类加载器的加载。
-
扩展加载源。如果需要加载从咔咔郭郭来的类,可以通过自定义加载器载入。
-
提高程序的安全性。在一般情况下,使用不同的类加载器去加载不同的功能模块,会提高应用程序的安全性。但是,如果涉及Java类型转换,则加载器反而容易产生不美好的事情。在做Java类型转换时,只有两个类型都是由同一个加载器所加载,才能进行类型转换,否则转换时会发生异常。
获取常见类的加载器
方式 | 加载器类型 |
---|---|
class对象.getClassLoader() | 获取class对象的类加载器 |
Thread.currentThread().getContextClassLoader() | 当前线程上下文的类加载器 |
ClassLoader.getSystemClassLoader() | 获取系统类加载器 |
classLoader对象.getParent() | 获取父类加载器 |
这些加载器,大多都是由应用类加载器来充当。
可以看到都是应用类加载器加载的。
引导类加载器结果为null,原因是引导类加载器是C++语言编写,并不是一个java对象,所以这里用null展示。
数组类特殊
数组类的Class对象,不是由类加载器创建的,而是在Java运行期JVM根据需要自动创建的。数组类的类加载器可以通过Class.getClassLoader()方法返回,如果数组元素是引用数据类型,类加载器与数组当中元素类型相同,如果数组元素类型是基本数据类型,就没有类加载器
System.out.println(int[][].class.getClassLoader());//输出nullSystem.out.println(ClassLoaderTest[][].class.getClassLoader());//输出sun.misc.Launcher$AppClassLoader@18b4aac2
源码分析
有必要学习类加载器的源码。
ClassLoader主要方法
抽象类ClassLoader的主要方法(内部没有抽象方法)如下。
1)public final ClassLoader getParent()该方法作用是返回该类加载器的父类加载器。
2)public Class<?>loadClass(String name)throws ClassNotFoundException该方法作用是加载名称为name的类,返回结果为java.lang.Class类的实例。如果找不到类,则抛出“ClassNotFoundException”异常。
该方法中的逻辑就是双亲委派模型的实现
具体操作就是:
-
sychronized保证同步没问题
-
查看自己是否加载过 通过findLoadedClass ,也就是protected final Class<?>findLoadedClass(String name) )
-
调用父加载器进行加载(如果父为空,调用findBootstrapClassOrNull加载)
-
父加载器失败,自己加载 通过findClass(name)
-
进行链接操作 resolveClass (也就是 验证,准备,解析 这三个操作)
这里的findClass方法就很重要了,最为加载器的兜底逻辑,负责查找二进制名为name的类,返回的是Class类实例。
protected Class<?>findClass(String name)throws ClassNotFoundException
在jdk1.2之后,官方已经不建议我们重写loadClass方法,因为loadClass方法中实现保证了双亲委派机制的逻辑。我们自己的逻辑建议写在findClass方法中。当loadClass()方法中父类加载器加载失败后,则会调用自己的findClass()方法来完成类加载,这样就可以保证自定义的类加载器也符合双亲委托模型。
在findClass()中,应该调用defineClass(),将找到的二进制流转换成Class对象。
protected final Class<?>defineClass(String name,byte [] b,int off,int len)
通过这个方法不仅能够通过class文件实例化Class实例对象,也可以通过其他方式实例化Class对象,如通过网络接收一个类的字节码,然后转换为byte字节流创建对应的Class对象
protected final void resolveClass(Class<?>c)
使用该方法可以使用类的Class对象创建完成的同时也被解析。前面我们说链接阶段主要是对字节码进行验证,为类变量分配内存并设置初始值同时将class文件中的符号引用转换为直接引用
也就是
SecureClassLoader与URLClassLoader
ClassLoader中有很多方法没有实现。SecureClassLoader新增了对Class源的验证,权限之类的方法。
他的子类URLClassLoader给ClassLoader众多没实现的方法提供了实现。例如findClass(),findResouce()方法。新增了通过URLClassPath类来协助获取Class字节码流的功能。
我们可以通过继承自URLClassLoader来避免实现过于复杂的findClass()和字节码获取代码。
ExtClassLoader与AppClassLoader
这两个类加载器都继承自URLClassLoader。是sun.misc.lanucher的内部静态类。sun.misc.lanucher主要用来启动主应用程序。
类加载调用方法
一般通过Class.forName(全限定名),或者classLoader实例.loadClass(全限定名)加载一个类。
不同的是Class方法会在加载到内存同时进行初始化。
而classLoader实例方法,只会加载到内存,不会触发实例化。
让自定义类加载器加载类的办法
如果在findClass中不做什么改变,那么类一般都会让父加载器也就是AppClassLoader给加载了。所以我们需要在loaderClass的时候传入类名,而不是全限定名,这样父加载器就找不到类,会交给自定义加载器加载。在findClass中我们再拼接出类的路径,找到类文件,然后进行加载。
双亲委派模型的改变
双亲委派机制并不是必须的,而是java设计者推荐的一种类加载器实现机制。
他的好处是:
-
避免重复加载
-
保护程序安全
打破双亲委派机制也无法破坏核心类库的唯一加载
在ClassLoader中的final defineClass方法中,为核心类库提供了一层保护机制。无论是什么类加载器,最终都会调用defineClass这个方法,这个方法final不能重写,在其内部调用preDefineClass方法,对核心类库进行保护。
他的劣势是:
因为我们只设计了父级类加载器的成员变量引用,那么我们的类去寻找其他的类的时候,只能先获取自己的ClassLoader,然后从ClassLoader中获取findLoadedClass(),找不到只能向上找loadedClass。所以无法访问下级类加载器加载的类。
破坏双亲委派机制的三种
为了兼容性
jdk1.2之前,并没有引入双亲委派机制,所以自定义类加载器很多都是通过重写loadClass实现的。在引入之后,为了兼容这些代码,就没有以技术手段防止loadClass被重写。创建了一个prorected findClass来代替重写loadClass。
SPI场景(不同的类加载器加载的类之间的交互)
简单来说就是接口定义在了启动类加载器中,而实现类定义在了其他类加载器中,当启动类加载器需要加载其他子类加载器路径中的类时,需要使用线程上下文类加载器(默认是应用程序类加载器),这样以上下文加载器为中介,使得启动类加载器中的代码也可以访问应用类加载器中的类。
线程上下文类加载器,实际上是一个帽子,主要看我们让哪一个类加载器来带上这个帽子。带上什么帽子起什么作用。原来的findLoadedClass是一条只能向上的线,通过线程上下文类加载器,这样就可以形成一个环。我们通常让APPClassLoader来充当线程上下文类加载器,这样AppClassloader,ExtratClassLoader,BootstrapClassLoader形成了一个环,那么这三个类加载器中加载的类就都相互可查询可见了。
为了热部署
追求程序的动态性,代码热部署,模块热替换等。
java并不天生支持热替换。热替换是指在程序的运行过程中,不停止服务,只通过替换程序文件来修改程序的行为。热替换的关键需求在于服务不能中断,修改必须立即表现正在运行的系统之中。
如果一个类已经加载到系统中,通过修改类文件,并无法让系统再来加载并重定义这个类。
但是如果我们就是想要重新加载并定义这个类呢?为了不影响程序的运行,我们不能卸载这个类,但是我们可以通过加载一个同名类来替换。要做到这件事,首先我们需要防止触发重复加载,我们需要换一个类加载器,这样JVM会认为是不同的类,然后加载进去,不能调用loadClass这样会交由AppClassLoader加载,就是会认为加载过了。
复习路线
JVM 复习1-CSDN博客
相关文章:
JVM 类加载器
字节码的结构 魔数u4 cafe babe 版本u4 52 java8 常量池计数器u2 从1开始,0索引留给不需要的情况 常量池 表 #1 -> #计数器-1 类标识符 u2 public final abstrat class annotion interface 之类 类索引u2 名字 父类索引u2 父类名字 接口计数器 u2 接口数…...
《C++长时间运行程序:驯服内存膨胀的“怪兽”》
在 C编程的世界里,当我们编写长时间运行的程序时,内存膨胀问题就像一个隐藏在暗处的“怪兽”,随时可能吞噬我们程序的性能和稳定性。无论是服务器应用程序、大型模拟系统还是其他长时间运行的关键任务软件,有效地处理内存膨胀问题…...
ELK之路第二步——可视化界面Kibana
Kibana 1.安装2.解压3.修改配置4.启动 这部分内容就比较简单了,水一片文章。 1.安装 需要梯子 官网下载链接:https://www.elastic.co/cn/downloads/past-releases/kibana-7-3-0 如果你去官网下载页面,点击下载是404报错,记得切换…...
Nature Medicine病理AI汇总|CONCH:病理图像分析的零样本学习模型·顶刊精析·24-10-30
小罗碎碎念 最近在整理24年发表在Nature Medicine上的病理AI文章,简单列了一个表。 接下来我将按照先后顺序,系统的把这13篇文献分析完。其中底色做了填充的,代表商业公司在本论文中占据了一作或通讯。 本期推文介绍的模型是CONCH࿰…...
通过不当变更导致 PostgreSQL 翻车的案例分析与防范
在数据库管理领域,PostgreSQL 凭借其强大的功能和稳定性,赢得了广泛的认可。然而,即便是如此稳健的系统,在不当的变更操作下,也可能遭遇性能下降、数据丢失甚至系统崩溃的风险。本文将通过一个具体案例,分析…...
Windows高级技巧:轻松实现多进程窗口的连接与管理
在Windows操作系统中,管理多个进程窗口可能是一项复杂的任务,特别是在自动化测试或多任务处理时。本文将介绍一种高效的方法,通过Python编程和AirtestIDE工具,实现多进程窗口的便捷连接与管理。同时,将提供具体的代码示…...
洪水淹没制图
原文链接:洪水淹没制图https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247624956&idx2&sn2557e56396eed7568d27baf694dc86fe&chksmfa8da91bcdfa200d307ea12ab9f52394ca6ef0bea3111bd8a873b34c950bcd9441c377f13674&token1392391660&…...
PHP的 CSRF、XSS 攻击和防范
CSRF攻击 CSRF(Cross-Site Request Forgery)攻击,也称为跨站请求伪造,是一种常见的网络安全威胁。在这种攻击中,攻击者利用已认证的用户身份,在用户不知情的情况下伪造请求,冒充用户的操作向目…...
怎么在线制作活码?二维码活码的简单制作技巧
进入数字化时代,二维码已经成为主要的一种内容分享方式,将内容生成活码二维码,可以方便内容的传输与存储,在日常生活中的很多场景都有二维码的应用。通过生成二维码的方式可以更简单快速的分享内容给其他人,有效提高获…...
Lua中实现异步HTTP请求的方法
Lua,作为一种轻量级的脚本语言,因其简洁和高效,在游戏开发、嵌入式系统以及互联网应用中得到了广泛的应用。本文将介绍如何在Lua中实现异步HTTP请求,并提供相应的代码实现,包括如何通过代理服务器发送请求。 异步HTTP…...
拓展学习-golang的基础语法和常用开发工具
golang的基础语法 golang的基础语法和其他语言大部分都差别不大,如果我们有学习过其他语言,比如JavaScript,php,java,python等,有其他语言的语法基础,那么我们学习golang将更容易上手。那我们直…...
得计算题者得天下!软考系统集成计算题详解!
软考中级系统集成项目管理工程师考试一共有《综合知识》和《案例分析》两门科目,而在这两科中都会涉及到计算题,特别是案例分析中,计算题每次考试都会占到一道大题,共25分,占到了科目总分的1/4,所以对于系统…...
在AdaBoost中每轮训练后,为什么错误分类的样本权重会增大e^2αt倍
在 AdaBoost 的每一轮迭代中,样本 i i i 的权重更新公式为: w t 1 , i w t , i ⋅ exp ( − α t y i G t ( x i ) ) Z t w_{t1,i} \frac{w_{t,i} \cdot \exp(-\alpha_t y_i G_t(x_i))}{Z_t} wt1,iZtwt,i⋅exp(−αtyiGt(xi)) …...
什么是数据中心?
数据中心是一个专门用于容纳大量联网计算机设备的设施,这些设备共同协作,以处理、存储和传输数据。现代社会中,大部分高科技公司都依赖数据中心来提供在线服务,例如网站、应用程序和云服务等。可以说,数据中心是互联网…...
【工具使用】VSCode如何将本地项目关联到远程的仓库 (vscode本地新项目与远程仓库建立链接)
在日常练习的项目中,我每次都在vscdoe编写前台代码,但是对于编写的代码,如何将本地项目关联到远程的仓库;这里做一下记录 文章目录 1、Gitee 新建远程仓库2、将本地的项目和远程仓库进行关联**3、将本地修改的代码推送到远程通过命…...
安全见闻-二进制与网络安全的关系
一、二进制的基本概念 二、二进制在网络安全中的重要性 三、二进制安全的概念与范畴 1. 二进制安全的定义 2. 范畴 四、二进制安全的渗透测试方法 1. 静态分析 2. 动态分析 3. 模糊测试 4. 漏洞利用 5. 代码审计 五、结论 学习视频泷羽sec:安全见闻&…...
MongoDB 部署指南:从 Linux 到 Docker 的全面讲解
一、MongoDB 简介 MongoDB 是一种 NoSQL 数据库,以文档模型存储数据,具备高性能、弹性扩展性和分布式架构等特点,非常适用于高并发和大数据量的场景。本文将从 Linux 和 Docker 环境开始讲解,帮助读者在不同环境下顺利部署 Mongo…...
Java AQS 源码
前言 相关系列 《Java & AQS & 目录》(持续更新)《Java & AQS & 源码》(学习过程/多有漏误/仅作参考/不再更新)《Java & AQS & 总结》(学习总结/最新最准/持续更新)《Java & …...
栈和队列(1)——栈
栈的基本概念 1. 栈的定义:只允许在一端进行插入或删除操作的线性表(可以理解为操作受限的线性表)。 2. 栈的特点:后进先出(LIFO)。 3. 栈的基本操作:初始化、销毁、进栈、出栈、读栈顶元素等…...
Java中的反射(Reflection)
先上两张图来系统的看一下反射的作用和具体的实现方法 接下来详细说一下反射的步骤以及之中使用的方法: 获取Class对象: 要使用反射,首先需要获得一个Class对象,该对象是反射的入口点。可以通过以下几种方式获取Class对象&#x…...
【IC验证】linux系统下基于QuestaSim的systemverilog仿真TCL命令
linux系统下基于QuestaSim的systemverilog仿真TCL命令 一.终端打开QuestaSim二.QuestaSim中TCL脚本指令1.仿真库的创建(vlib)-非必要2.编译命令(vlog)3.仿真命令(vlog)4.运行命令(run࿰…...
Python图像处理库PIL,实现旋转缩放、剪切拼接以及滤波
文章目录 切割缩放和旋转拼接 PIL的Image类,提供了一些常用的图像处理方法。 切割缩放和旋转 PIL可以很方便地实现如下效果 代码如下 from PIL import Image path lena.jpg img Image.open(path) # 读取 img.resize((50, 50), resampleImage.Resampling.NEARE…...
xhr的readyState和status
XMLHttpRequest(XHR)对象中的readyState和status用于监控异步 HTTP 请求的状态。它们分别表示请求的当前阶段和服务器的响应状态。 readyState 用于判断请求所处的阶段,确保数据完全接收。 status 用于判断请求的结果状态(如200表…...
Rust 力扣 - 238. 除自身以外数组的乘积
文章目录 题目描述题解思路题解代码题解链接 题目描述 题解思路 这题主要有个关键点,就是元素能取0,然后我们分类讨论元素为0的数量 如果数组中存在至少两个元素为0,则每个元素的除自身以外的乘积为0如果数组中仅存在一个0,则为…...
【Vue框架】基础语法练习(1)
其实更多知识点已经在Vue.js官网十分清楚了,大家也可以去官网进行更细节的学习 https://cn.vuejs.org/ 说明:目前最新是Vue3版本的,但是Vue2已经深得人心,所以就是可以支持二者合用。它们最大的区别就是Vue3是组合式API…...
开源一款基于 JAVA 的仓库管理系统,支持三方物流和厂内物流,包含 PDA 和 WEB 端的源码
大家好,我是一颗甜苞谷,今天分享一款基于 JAVA 的仓库管理系统,支持三方物流和厂内物流,包含 PDA 和 WEB 端的源码。 前言 在当前的物流仓储行业,企业面临着信息化升级的迫切需求,但往往受限于高昂的软件采购和维护成本。现有的…...
开源一套基于若依的wms仓库管理系统,支持lodop和网页打印入库单、出库单的源码
大家好,我是一颗甜苞谷,今天分享一款基于若依的wms仓库管理系统,支持lodop和网页打印入库单、出库单的源码。 前言 在当今快速发展的商业环境中,库存管理对于企业来说至关重要。然而,许多企业仍然依赖于传统的、手动…...
HTML+JavaScript案例分享: 打造经典俄罗斯方块,详解实现全过程
在本文中,我们将深入探讨如何使用 JavaScript 实现经典的俄罗斯方块游戏。俄罗斯方块是一款广为人知的益智游戏,通过操纵各种形状的方块,使其在游戏区域内排列整齐,以消除完整的行来获得分数。 效果图如下: 一、游戏界面与布局 我们首先使用 HTML 和 CSS 来创建游戏的界面…...
【网页布局技术】项目五 使用CSS设置导航栏
《CSSDIV网页样式与布局案例教程》 徐琴 目录 任务一 制作简单纵向导航栏支撑知识点1.合理利用display:block属性2.利用margin-bottom设置间隔效果3.利用border设置特殊边框 任务二 制作简单横向导航栏任务三 制作带图片效果的横向导航栏任务…...
自学网络安全,网络安全入门学习路线,收藏这篇就够了
在当今高度数字化的时代,网络安全已经成为了一个至关重要的领域。随着网络威胁的不断演变和增长,对于专业网络安全人才的需求也在急剧上升。对于那些对网络安全充满热情并且渴望自学成才的人来说,制定一个系统、全面且高效的学习路线和规划是…...
wordpress畅言插件/自媒体怎么入门
小程序赛道要逆天了,继微信小程序,百度小程序,支付宝小程序,头条小程序,360PC小程序之后,中国移动宣布也将进入小程序赛道,推出短信小程序,覆盖生活吃穿住行所有场景! 了解到&#x…...
开原 铁岭网站建设/网络营销策划书包括哪些内容
原文地址:你必须知道的地理坐标系和投影坐标系 文章条理清晰,内容通俗易懂 还可以参考另一篇文章:GISer梳理的我国常用的坐标系及相关知识 1、基本概念 地理坐标系:为球面坐标。 参考平面地是椭球面,坐标单位ÿ…...
东莞网站se/seo网络推广什么意思
处理过线上问题的同学基本上都会遇到系统突然运行缓慢,CPU 100%,以及 Full GC 次数过多的问题。 当然,这些问题最终导致的直观现象就是系统运行缓慢,并且有大量的报警。 本文主要针对系统运行缓慢这一问题,提供该问题…...
wordpress首页自定义缩略图/阿里大数据平台
1. AOP的相关概念1.1 AOP概述1.1.1 什么是AOPAOP:全程是Aspect Oriented Programming 即面向切面编程。是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重…...
广州建设工程网站/东莞关键词优化软件
神农氏 神农氏据说长得像牛魔王——“牛首人身”,不过他看上去并不像牛魔王那样粗暴。事实上他极具仁慈爱心。这位优秀青年,最大的爱好就是拎了一根棍子,在西部的黄土高坡上考察野生植物,是个十足内向的家伙。他到处收集植物样…...
网站建设的实训报告/自己如何制作网站
目 录 摘 要 I Abstract II 1 前言 1 1.1 研究背景及意义 1 1.2 国内外研究现状 2 1.3 本文研究思路与结构 3 2 系统开发技术介绍 4 2.1 Java语言 5 2.2 Spring框架简介 6 2.3 Spring Boot 框架简介 6 2.4 MyBatis 框架简介 7 2.5 开发环境 8 3 系统需求分析 9 3.1 需求分析 9 …...