JVM类加载机制详解

news2024/11/23 11:44:52

JVM类加载运行全过程

运行Math类的main函数,启动程序时,首先需要通过类加载器把类加载到JVM。

package com.cold;

public class Math {

    public int compute() {
        int a = 1;
        int b = 2;
        int c = (a + b) * 10;
        return c;
    }

    public static void main(String[] args) {
        Math math = new Math();
        math.compute();
    }
}

在这里插入图片描述

loadClass的类加载

其中loadClass的类加载过程有如下几步:

加载 >> 验证 >> 准备 >> 解析 >> 初始化 >> 使用 >> 卸载

  • 加载: 在硬盘上查找并通过IO读入字节码文件,使用到类时才会加载,例如调用类的main()方法,new对象等等,在加载阶段会在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
  • 验证: 校验字节码文件的正确性
  • 准备: 给类的静态变量分配内存,并赋予默认值。
  • 解析: 将符号引用替换为直接引用,该阶段会把一些静态方法(符号引用,比如main()方法()替换为指向数据所存内存的指针或句柄等(直接引用),这是所谓的静态链接过程(类加载期间完成),动态链接是在程序运行期间完成的将符号引用替换为直接引用。
  • 初始化: 对类的静态变量初始化为指定的值,执行静态代码块。

类被加载到方法区中的主要信息: 运行时常量池、类型信息、字段信息、方法信息、类加载器的引用、对应class实例的引用。

类加载器的引用: 这个类到类加载器实例的引用

对应class实例的引用: 类加载器在加载类信息放到方法区中后,会创建一个对应的Class 类型的对象实例放到堆(Heap)中, 作为开发人员访问方法区中类定义的入口和切入点。

类加载属于懒加载,程序运行时使用到什么类就会加载什么类。

类加载器和双亲委派机制

类加载过程主要是通过类加载器来实现的,Java中有以下几种类加载器:

  • 引导类加载器: 负责加载支撑JVM运行的位于JRE的lib目录下的核心类库,比如rt.jar、charsets.jar等
  • 扩展类加载器(ExtClassLoader): 负责加载支撑JVM运行的位于JRE的lib目录下的ext扩展目录中的JAR类包
  • 应用程序类加载器(AppClassLoader): 负责加载ClassPath路径下的类包,主要就是加载你自己写的那些类
  • 自定义加载器: 负责加载用户自定义路径下的类包

类加载示例

package com.cold;

import sun.misc.Launcher;

import java.net.URL;

public class TestClassLoader {

    public static void main(String[] args) {
        System.out.println(String.class.getClassLoader());
        System.out.println(com.sun.crypto.provider.DESKeyFactory.class.getClassLoader());
        System.out.println(TestClassLoader.class.getClassLoader());

        System.out.println();

        ClassLoader appClassLoader = ClassLoader.getSystemClassLoader();
        ClassLoader extClassLoader = appClassLoader.getParent();
        ClassLoader bootstrapClassLoader = extClassLoader.getParent();

        System.out.println("the bootstrapClassLoader : " + bootstrapClassLoader);
        System.out.println("the extClassLoader : " + extClassLoader);
        System.out.println("the appClassLoader : " + appClassLoader);

        System.out.println();
        System.out.println("bootstrapLoader加载以下文件:");
        URL[] urls = Launcher.getBootstrapClassPath().getURLs();
        for (int i = 0; i < urls.length; i++) {
            System.out.println(urls[i]);
        }

        System.out.println();
        System.out.println("extClassloader加载以下文件:");
        System.out.println(System.getProperty("java.ext.dirs"));

        System.out.println();
        System.out.println("appClassLoader加载以下文件:");
        System.out.println(System.getProperty("java.class.path"));
    }

}

输出结果

null
sun.misc.Launcher$ExtClassLoader@77459877
sun.misc.Launcher$AppClassLoader@18b4aac2

the bootstrapClassLoader : null
the extClassLoader : sun.misc.Launcher$ExtClassLoader@77459877
the appClassLoader : sun.misc.Launcher$AppClassLoader@18b4aac2

bootstrapLoader加载以下文件:
file:/D:/Program%20Files/Java/jdk-1.8/jre/lib/resources.jar
file:/D:/Program%20Files/Java/jdk-1.8/jre/lib/rt.jar
file:/D:/Program%20Files/Java/jdk-1.8/jre/lib/jsse.jar
file:/D:/Program%20Files/Java/jdk-1.8/jre/lib/jce.jar
file:/D:/Program%20Files/Java/jdk-1.8/jre/lib/charsets.jar
file:/D:/Program%20Files/Java/jdk-1.8/jre/lib/jfr.jar
file:/D:/Program%20Files/Java/jdk-1.8/jre/classes

extClassloader加载以下文件:
D:\Program Files\Java\jdk-1.8\jre\lib\ext;C:\Windows\Sun\Java\lib\ext

appClassLoader加载以下文件:
D:\Program Files\Java\jdk-1.8\jre\lib\charsets.jar;D:\Program Files\Java\jdk-1.8\jre\lib\deploy.jar;D:\Program Files\Java\jdk-1.8\jre\lib\ext\access-bridge-64.jar;D:\Program Files\Java\jdk-1.8\jre\lib\ext\cldrdata.jar;D:\Program Files\Java\jdk-1.8\jre\lib\ext\dnsns.jar;D:\Program Files\Java\jdk-1.8\jre\lib\ext\jaccess.jar;D:\Program Files\Java\jdk-1.8\jre\lib\ext\jfxrt.jar;D:\Program Files\Java\jdk-1.8\jre\lib\ext\localedata.jar;D:\Program Files\Java\jdk-1.8\jre\lib\ext\nashorn.jar;D:\Program Files\Java\jdk-1.8\jre\lib\ext\sunec.jar;D:\Program Files\Java\jdk-1.8\jre\lib\ext\sunjce_provider.jar;D:\Program Files\Java\jdk-1.8\jre\lib\ext\sunmscapi.jar;D:\Program Files\Java\jdk-1.8\jre\lib\ext\sunpkcs11.jar;D:\Program Files\Java\jdk-1.8\jre\lib\ext\zipfs.jar;D:\Program Files\Java\jdk-1.8\jre\lib\javaws.jar;D:\Program Files\Java\jdk-1.8\jre\lib\jce.jar;D:\Program Files\Java\jdk-1.8\jre\lib\jfr.jar;D:\Program Files\Java\jdk-1.8\jre\lib\jfxswt.jar;D:\Program Files\Java\jdk-1.8\jre\lib\jsse.jar;D:\Program Files\Java\jdk-1.8\jre\lib\management-agent.jar;D:\Program Files\Java\jdk-1.8\jre\lib\plugin.jar;D:\Program Files\Java\jdk-1.8\jre\lib\resources.jar;D:\Program Files\Java\jdk-1.8\jre\lib\rt.jar;E:\working_folder\code\test-project\target\classes;D:\Program Files\JetBrains\IntelliJ IDEA 2023.1.1\lib\idea_rt.jar

类加载器初始化过程:

参考类运行加载全过程图,可知其中会创建JVM启动器实例sun.misc.Launcher

在Launcher构造方法内部,其创建了两个类加载器,分别是sun.misc.Launcher.ExtClassLoader(扩展类加载器)和sun.misc.Launcher.AppClassLoader(应用类加载器)。

JVM默认使用Launcher的getClassLoader()方法返回的类加载器AppClassLoader的实例加载我们的应用程序。

在这里插入图片描述

双亲委派机制

这里类加载其实就有一个双亲委派机制,加载某个类时会先委托父加载器寻找目标类,找不到再委托上层父加载器加载,如果所有父加载器在自己的加载类路径下都找不到目标类,则在自己的类加载路径中查找并载入目标类。

比如我们的Math类,最先会找应用程序类加载器加载,应用程序类加载器会先委托扩展类加载器加载,扩展类加载器再委托引导类加载器,顶层引导类加载器在自己的类加载路径里找了半天没找到Math类,则向下退回加载Math类的请求,扩展类加载器收到回复就自己加载,在自己的类加载路径里找了半天也没找到Math类,又向下退回Math类的加载请求给应用程序类加载器,应用程序类加载器于是在自己的类加载路径里找Math类,结果找到了就自己加载了。

在这里插入图片描述

我们来看下应用程序类加载器AppClassLoader加载类的双亲委派机制源码,AppClassLoader的loadClass方法最终会调用其父类ClassLoader的loadClass方法,该方法的大体逻辑如下:

  1. 首先,检查一下指定名称的类是否已经加载过,如果加载过了,就不需要再加载,直接返回。
  2. 如果此类没有加载过,那么,再判断一下是否有父加载器;如果有父加载器,则由父加载器加载(即调用parent.loadClass(name, false);).或者是调用bootstrap类加载器来加载。
  3. 如果父加载器及bootstrap类加载器都没有找到指定的类,那么调用当前类加载器的findClass方法来完成类加载。

在这里插入图片描述

为什么要设计双亲委派机制?

沙箱安全机制: 自己写的java.lang.String.class类不会被加载,这样便可以防止核心API库被随意篡改

避免类的重复加载: 当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次,保证被加载类的唯一性

全盘负责委托机制

“全盘负责”是指当一个ClassLoder装载一个类时,除非显示的使用另外一个ClassLoder,该类所依赖及引用的类也由这个ClassLoder载入。

自定义类加载器示例

自定义类加载器只需要继承 java.lang.ClassLoader 类,该类有两个核心方法,一个是loadClass(String, boolean),实现了双亲委派机制,还有一个方法是findClass,默认实现是空方法,所以我们自定义类加载器主要是重写findClass方法。

package com.cold;

import java.io.FileInputStream;
import java.io.IOException;

public class MyClassLoaderTest {

    static class MyClassLoader extends ClassLoader{
        private String classPath;

        public MyClassLoader(String classPath){
            this.classPath = classPath;
        }

        private byte[] loadByte(String name) throws IOException {
            name = name.replaceAll("\\.", "/");
            FileInputStream is = new FileInputStream(classPath+"/"+name+".class");
            int len = is.available();
            byte[] data = new byte[len];
            is.read(data);
            is.close();
            return data;
        }

        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            try {
                byte[] data = loadByte(name);
                //defineClass将一个字节数组转为Class对象,这个字节数组是class文件读取后最终的字节数组。
                return defineClass(name,data,0,data.length);
            } catch (Exception e) {
                e.printStackTrace();
                throw new ClassNotFoundException();
            }
        }
    }

    public static void main(String[] args) throws Exception{
        //初始化自定义类加载器,会先初始化父类ClassLoader,其中会把自定义类加载器的父加载器设置为应用程序类加载器AppClassLoader
        MyClassLoader classLoader = new MyClassLoader("E:/test");
        //复制User.class文件到D:/test/com/cold目录下
        Class<?> clazz = classLoader.loadClass("com.cold.User");
        // 删除原有的User类输出的结果为com.cold.MyClassLoaderTest$MyClassLoader
        // 不删除原有的User类输出的结果为sun.misc.Launcher$AppClassLoader
        System.out.println(clazz.getClassLoader().getClass().getName());
    }
}

Tomcat打破双亲委派机制

以Tomcat类加载为例,Tomcat 如果使用默认的双亲委派类加载机制行不行?

我们思考一下:Tomcat是个web容器, 那么它要解决什么问题:

  1. 一个web容器可能需要部署两个应用程序,不同的应用程序可能会依赖同一个第三方类库的不同版本,不能要求同一个类库在同一个服务器只有一份,因此要保证每个应用程序的类库都是独立的,保证相互隔离。
  2. 部署在同一个web容器中相同的类库相同的版本可以共享。否则,如果服务器有10个应用程序,那么要有10份相同的类库加载进虚拟机。
  3. web容器也有自己依赖的类库,不能与应用程序的类库混淆。基于安全考虑,应该让容器的类库和程序的类库隔离开来。
  4. web容器要支持jsp的修改,我们知道,jsp 文件最终也是要编译成class文件才能在虚拟机中运行,但程序运行后修改jsp已经是司空见惯的事情, web容器需要支持 jsp 修改后不用重启。

再看看我们的问题:Tomcat 如果使用默认的双亲委派类加载机制行不行?

答案是不行的。为什么?

第一个问题,如果使用默认的类加载器机制,那么是无法加载两个相同类库的不同版本的,默认的类加器是不管你是什么版本的,只在乎你的全限定类名,并且只有一份。

第二个问题,默认的类加载器是能够实现的,因为他的职责就是保证唯一性。

第三个问题和第一个问题一样。

我们再看第四个问题,我们想我们要怎么实现jsp文件的热加载,jsp 文件其实也就是class文件,那么如果修改了,但类名还是一样,类加载器会直接取方法区中已经存在的,修改后的jsp是不会重新加载的。那么怎么办呢?我们可以直接卸载掉这jsp文件的类加载器,所以你应该想到了,每个jsp文件对应一个唯一的类加载器,当一个jsp文件修改了,就直接卸载这个jsp类加载器。重新创建类加载器,重新加载jsp文件。

Tomcat自定义加载器详解

在这里插入图片描述

tomcat的几个主要类加载器:

  • commonLoader: Tomcat最基本的类加载器,加载路径中的class可以被Tomcat容器本身以及各个Webapp访问;
  • catalinaLoader: Tomcat容器私有的类加载器,加载路径中的class对于Webapp不可见;
  • sharedLoader: 各个Webapp共享的类加载器,加载路径中的class对于所有Webapp可见,但是对于Tomcat容器不可见;
  • WebappClassLoader: 各个Webapp私有的类加载器,加载路径中的class只对当前Webapp可见,比如加载war包里相关的类,每个war包应用都有自己的WebappClassLoader,实现相互隔离,比如不同war包应用引入了不同的spring版本,这样实现就能加载各自的spring版本;

从图中的委派关系中可以看出:

CommonClassLoader能加载的类都可以被CatalinaClassLoader和SharedClassLoader使用,从而实现了公有类库的共用,而CatalinaClassLoader和SharedClassLoader自己能加载的类则与对方相互隔离。

WebAppClassLoader可以使用SharedClassLoader加载到的类,但各个WebAppClassLoader实例之间相互隔离。

而JasperLoader的加载范围仅仅是这个JSP文件所编译出来的那一个.Class文件,它出现的目的就是为了被丢弃:当Web容器检测到JSP文件被修改时,会替换掉目前的JasperLoader的实例,并通过再建立一个新的Jsp类加载器来实现JSP文件的热加载功能。

模拟实现Tomcat的webappClassLoader加载自己war包应用内不同版本类实现相互共存与隔离

只需重写Class<?> loadClass(String name, boolean resolve),实现自己的加载逻辑,不委派给双亲加载。

同一个JVM内,两个相同包名和类名的类对象可以共存,因为他们的类加载器可以不一样,所以看两个类对象是否是同一个,除了看类的包名和类名是否都相同之外,还需要他们的类加载器也是同一个才能认为他们是同一个。

package com.cold;

import java.io.FileInputStream;
import java.io.IOException;

public class MyClassLoaderTest {


    static class MyClassLoader extends ClassLoader{
        private String classPath;

        public MyClassLoader(String classPath){
            this.classPath = classPath;
        }

        private byte[] loadByte(String name) throws IOException {
            name = name.replaceAll("\\.", "/");
            FileInputStream is = new FileInputStream(classPath+"/"+name+".class");
            int len = is.available();
            byte[] data = new byte[len];
            is.read(data);
            is.close();
            return data;
        }

        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            try {
                byte[] data = loadByte(name);
                //defineClass将一个字节数组转为Class对象,这个字节数组是class文件读取后最终的字节数组。
                return defineClass(name,data,0,data.length);
            } catch (Exception e) {
                e.printStackTrace();
                throw new ClassNotFoundException();
            }
        }

        @Override
        protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
            synchronized (getClassLoadingLock(name)) {
                // First, check if the class has already been loaded
                Class<?> c = findLoadedClass(name);
                if (c == null) {
                    long t0 = System.nanoTime();

                    //非自定义的类还是走双亲委派加载
                    if(!name.startsWith("com.cold.jvm")){
                        c = this.getParent().loadClass(name);
                    }else {
                        c = findClass(name);
                    }


                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();

                }
                if (resolve) {
                    resolveClass(c);
                }
                return c;
            }
        }
    }

    public static void main(String[] args) throws Exception{
        //初始化自定义类加载器,会先初始化父类ClassLoader,其中会把自定义类加载器的父加载器设置为应用程序类加载器AppClassLoader
        MyClassLoader classLoader = new MyClassLoader("E:/test");
        //复制User.class文件到D:/test/com/cold目录下
        Class<?> clazz = classLoader.loadClass("com.cold.jvm.User");
        // 输出结果com.cold.MyClassLoaderTest$MyClassLoader
        System.out.println(clazz.getClassLoader().getClass().getName());
    }
}

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

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

相关文章

如何将中文翻译成荷兰语?

随着中国的崛起&#xff0c;荷兰与中国的交流日益频繁。越来越多的企业和个人需要荷兰语翻译服务。那么&#xff0c;如何将中文翻译成荷兰语&#xff0c;北京哪家翻译公司比较专业&#xff1f; 专业人士指出&#xff0c;要提供优质的荷兰语翻译服务&#xff0c;不仅需要扎实的荷…

【hive-解决】HiveAccessControlException Permission denied: CREATEFUNCTION

文章目录 一.任务描述二. 解决 一.任务描述 Error while compiling statement: FAILED: HiveAccessControlException Permission denied: Principal [nameroot, typeUSER] does not have following privileges for operation CREATEFUNCTION [ADMIN PRIVILEGE on INPUT, ADMIN…

CSGO的那些事儿:CS2这么差,为什么不改回CS1?

揭秘csgo饰品涨价背后的残酷真相 1、V社现在更新内容集中在游戏性的修复方面。 所以原来期望的新地图新大行动等&#xff0c;要等到游戏本体趋于稳定后才更新。但是&#xff0c;因为距离下一个大型活动&#xff0c;也就是丹麦major还有5个月时间&#xff0c;那这之间必然要有一…

百度智能小程序源码系统:打造极致用户体验的关键 带完整搭建教程

大家好啊&#xff0c;今天罗峰来给大家分享一款百度智能小程序系统源码。一起来看看吧。 百度智能小程序源码系统是百度从做智能小程序的第一天开始就致力于打造真正开源开放的生态的产物。作为目前业内唯一真正开源的平台&#xff0c;百度智能小程序将开放性放在重要位置&…

kubernetes 高可用集群

目录 一、haproxy负载均衡 二、pacemaker高可用 三、部署control-plane 四、部署worker node 实验环境 主机名 IP 角色 docker 192.168.67.10 harbor k8s1 192.168.67.11 control-plane k8s2 192.168.67.12 control-plane k8s3 192.168.67.13 control-plane k8s…

数字逻辑电路基础-组合逻辑电路之复用器

文章目录 一、复用器简介二、verilog源码三、综合及仿真结果一、复用器简介 本文介绍数字逻辑电路中一种常用的基础组合逻辑电路-两选一复用器,顾名思义,它的功能就是通过一个控制信号来选择两个输入中之一作为输出。 它的逻辑表达式为:out = ~sa + sb 它的逻辑真值表为:…

元宇宙数字展厅无代码编辑工具的功能特点

商场如战场&#xff0c;营销是每个企业都必须重视的环节。随着科技的发展&#xff0c;3D展示营销制作平台作为企业快速搭建3D互动展厅的SaaS平台&#xff0c;逐渐崭露头角&#xff0c;为企业提供了诸多便利&#xff0c;让营销变得更加高效和引人入胜。 为企业提供身临其境的产品…

IDEA 中设置 File Header 以及自定义类、方法注释模板的方法

目录 1 设置 File Header2 自定义类、方法注释生成类注解模板生成方法注解模板 1 设置 File Header File -> Settings -> File and Code Templates -> Includes -> File Header -> 编辑 2 自定义类、方法注释 File -> Settings -> Live Templates -&g…

2023年最新软件安装管家目录

最新软件安装管家目录 软件目录 ①【电脑办公】电脑系统&#xff08;直接安装&#xff09;Win7Win8Win10OfficeOffice激活office2003office2007office2010office2013office2016office2019office365office2021wps2021Projectproject2007project2010project2016project2019projec…

二层、三层交换机之间到底有什么区别?

简单地说 二层交换机&#xff0c;没有充当三层网关角色的能力&#xff08;Capability&#xff09;。三层交换机&#xff0c;首先也是二层交换机。但是&#xff0c;它有一个额外的能力&#xff08;Capability&#xff09;&#xff0c;软件配置一下&#xff0c;可以充当三层网关…

【嵌入式C】栈内存与printf,代码正确运行,删掉 printf 代码就崩溃了??

目录 1. 删掉 printf 代码就崩溃了2. 运行代码为什么报错2.1 为什么程序报错 Segmentation fault &#xff1f;2.2 为什么程序每次都稳定的报错&#xff1f;2.3 研究一下两个局部变量的值和地址&#xff1f; 3. 为什么加一个 “\n”就可以正确执行&#xff1f;疑问&#xff1f;…

黑五来袭,如何利用海外代理进行助力

黑五作为下半年年度尤为重要的一个节日&#xff0c;是各大商家的必争之地&#xff0c;那么海外代理是如何帮助跨境商家做好店铺管理和营销呢&#xff1f; 为什么跨境人都关注海外代理&#xff0c;下面我们来进行介绍。 一、什么是海外代理 海外代理就是我们所说的&#xff1…

Snipaste 截图悬浮工具【实用教程】

下载安装 Snipaste windows64位版本下载链接&#xff1a;https://pan.baidu.com/s/1i2L3JHxOGqkmX3lj2fUVHA?pwdeut6 无需安装&#xff0c;解压后即可使用 其他版本见官网 https://zh.snipaste.com/download.html 启动 Snipaste 双击解压后文件夹 Snipaste-2.8.8-Beta-x64 中…

零基础安装分布式数据服务注册系统

一、先安装VM虚拟机&#xff0c;安装最新的ubuntu22系统&#xff0c; 先安装mysql&#xff0c; sudo apt install mysql-server sudo mysql_secure_installation 根据自己需求选择 密码安全级别时&#xff0c;选择n 删除匿名用户&#xff1f;&#xff08;按y|Y表示是&…

【字符编码系列一】ASCII编码是什么?

介绍 ASCII 编码于 1967 年第一次发布&#xff0c;最后一次更新是在 1986 年&#xff0c;迄今为止共收录了 128 个字符&#xff0c;包含了基本的拉丁字母&#xff08;英文字母&#xff09;、阿拉伯数字&#xff08;也就是 1234567890&#xff09;、标点符号&#xff08;,.!等&…

duplicate复制数据库单个数据文件复制失败报错rman-03009 ora-03113

duplicate复制数据库单个数据文件复制失败报错rman-03009 ora-03113 搭建dg过程中&#xff0c;发现有一个数据文件在复制过程中没有复制过来&#xff0c;在备库数据文件目录找不到这个数据文件 处理方法&#xff1a; 第一步&#xff1a;主库备份86#数据文件 C:\Users\Admi…

信息安全相关标准

GB/T 25070-2019 信息安全技术 网络安全等级保护安全设计技术要求 在线预览|GB/T 25070-2019 (gb688.cn) 每一级安全保护环境分为安全计算环境&#xff0c;安全区域边界&#xff0c;安全通信网络。 一级通用安全计算环境 二级通用安全 计算环境 三级 通用安全计算环境 第四级…

漏电继电器 JELR-(120)FG AC220V 零序电流互感器 孔径φ45 上海约瑟

JELR-FG系列漏电继电器 JELR-15FG漏电继电器&#xff1b; JELR-25FG漏电继电器&#xff1b; JELR-32FG漏电继电器&#xff1b; JELR-63FG漏电继电器&#xff1b; JELR-100FG漏电继电器; JELR-120FG漏电继电器&#xff1b; JELR-160FG漏电继电器&#xff1b; JELR-200FG…

调用本地大模型实现聊天机器人ChatBot

AWS Instance本地部署大模型 AWS上申请带GPU的instance&#xff0c;例如g4dn系列&#xff0c;申请instance后安装CUDA的driver&#xff0c;driver安装完成后&#xff0c;就可以在带gpu的instance上部署开源的大模型了。如果想了解在aws上部署本地模型细节&#xff0c;可以阅读…

【网络奇遇记】那年我与计算机网络的初相识 —— 网络的体系结构

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;网络奇遇记、数据结构 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 一. 常见的三种计算机网络体系结构1.1 开放系统互连参考模型1.2 TCP/IP参考模型1.3 原理参考模型 二…