JVM的内容

news2024/7/2 20:14:32

0、Java基础考点

请添加图片描述

1、谈谈你对Java的理解

  • 平台无关性(一次编译,到处运行)
  • GC(垃圾清理)
  • 语言特性(泛型、反射)
  • 面向对象(封装、继承、多态)
  • 类库
  • 异常处理

2、Java是如何实现平台无关性的(一处编译,到处运行)

  • 编译时(语法和语义进行检测)
  • 运行时

javac将源码编译为.class字节码文件。

javap java自带的反编译工具
javac test.java
javap -c test

请添加图片描述

Java源码首先被编译成字节码,再由不同平台的JVM进行解析,Java语言在不同的平台上运行时不需要进行重新编译,Java虚拟机在执行字节码的时候,把字节码转换成具体平台上的机器指令。

为什么JVM不直接将源码解析成机器码去执行?

  • 准备工作:每次执行都需要各种检查。(编译时先进行语法和语义检查)
  • 兼容性:也可以将别的语言解析成字节码。(别的语言也可以编译为.class字节码文件)
  • 平台无关性:可以实现平台无关性。一次编译,到处执行。

3、JVM如何加载 .class文件

Java虚拟机

JVM屏蔽底层操作系统的不同,减少基于原生语言开发的复杂性。

  • 内存结构模型
  • GC

请添加图片描述

  • Class loader:依据特定格式,加载dass文件到內存。
  • Execution Engine:对命令进行解析。
  • Native Interface:融合不同开发语言的原生库为Java所用。
  • RuntimeDataArea:JM内存空间结构模型。

JVM主要有Class Loader、RuntimData Area 、Execution Engine、Native Interface四部分组成,主要通过Class Loader将符合格式要求的文件,加载到内存中。并通过Execution Engine解析内部字节码,提交给操作系统执行。

4、谈谈反射

  • JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
  • 对于任意一个对象,都能够调用它的任意方法和属性;
  • 这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

待调用方法:

public class Robot {

    private String name;

    //    公共的方法
    public void sayHi(String hello) {
        System.out.println(hello + ":" + name);
    }

    //    私有化的方法
    private String throwHello(String tag) {
        return "Hello :" + tag;
    }
}

调用:

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;


public class Test {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        Class robot = Class.forName("com.lydms.IO.Robot");
        Robot r = (Robot) robot.newInstance();
        System.out.println("Class name is" + robot.getName());


//        1、执行private方法throwHello,并接受返回值
        Method throwHello = robot.getDeclaredMethod("throwHello", String.class);
//        将私有化方法设置为可见
        throwHello.setAccessible(true);
//        执行方法,并传入参数,获取返回值
        Object str = throwHello.invoke(r, "Bob");
        System.out.println("Result is " + str);


//        2、执行publi方法sayHi,并指定name的值
        Method sayHi = robot.getMethod("sayHi", String.class);
        sayHi.invoke(r, "Welcome");


//        3、执行publi方法sayHi,并指定name的值
//        获取私有变量的对象
        Field name = robot.getDeclaredField("name");
//        给私有变量设置可见
        name.setAccessible(true);
        name.set(r, "Alice");
        sayHi.invoke(r, "Welcome");
    }
}

类从编译到执行的过程

  • 编译器将 Robot java源文件编译为 Robot.class字节码文件
  • Classloader将字节码转换为JVM中的 Class< Robot>对象
  • JVM利用Class< Robot>对象实例化为 Robot对象

5、谈谈ClassLoader

Classloader 在 Java 中有着非常重要的作用,它主要工作在 Class装载的加载阶段,其主要作用是从系统外部获得 Class二进制数据流。它是Java的核心组件,所有的Class都是由 Classloader进行加载的,Classloader负责通过将 Class文件里的二进制数据流装载进系统,然后交绐Java虚拟机进行连接、初始化等操作。

ClassLoader的种类

  • BootstrapClassLoader:C++编写,加载核心库java.*。
  • Extclassloader:Java编写,加载扩展库 Javax.*。
  • AppClassLoader:Java编写,加载程序所在目录方法。
  • 自定义 Classloader:Java编写,定制化加载。

Extclassloader:(扩展库 Javax.*)

String property = System.getProperty("java.ext.dirs");

AppClassLoader:(加载程序所在目录)

String property = System.getProperty("java.class.path");

自定义ClassLoader的实现

关键函数

寻找class文件,读取二进制文件

protected Class<?> findClass(String name) throws ClassNotFoundException {
    throw new ClassNotFoundException(name);
}

定义类(将字节流转为class)

protected final Class<?> defineClass(byte[] b, int off, int len)throws ClassFormatError{
    return defineClass(null, b, off, len, null);
}

根据名称/位置加载Class文件,调用defineClass去解析字节流

待执行文件:

public class Wali{
    static{
         System.out.println("Hello Wali");
        
    }
}

自定义类加载器

import java.io.*;
public class MyClassLoader extends ClassLoader {
    private String path;
    private String classLoaderName;


    public MyClassLoader(String path, String classLoaderName) {
        this.path = path;
        this.classLoaderName = classLoaderName;
    }


//    用于寻找类文件
    @Override
    public Class findClass(String name) {
        byte[] b = loadClassData(name);
        return defineClass(name, b, 0, b.length);
    }


//    用于加载类文件
    private byte[] loadClassData(String name) {
        name = path + name + ".class";
        InputStream in = null;
        ByteArrayOutputStream out = null;
        try {
            in = new FileInputStream(new File(name));
            out = new ByteArrayOutputStream();
            int i = 0;
            while ((i = in.read()) != -1) {
                out.write(i);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return out.toByteArray();
    }
}

调用类加载器

 public class ClassLoaderChecker {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        MyClassLoader m = new MyClassLoader("D:\\", "myClass");
        Class<?> c = m.loadClass("Wali");
//        会调用自定义的findClass( )
        ClassLoader classLoader = c.getClassLoader();
        System.out.println(classLoader);
//        执行加载文件里的方法
        c.newInstance();
    }
}

类加载器的双亲委派机制

请添加图片描述

protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
    synchronized (getClassLoadingLock(name)) {
        // 1、首先,检查是否已经加载的类
        Class<?> c = findLoadedClass(name);
        if (c == null) {
            long t0 = System.nanoTime();
            try {
                if (parent != null) {
                     2、没有的话,代用父类的加载器
                    c = parent.loadClass(name, false);
                } else {
                    c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {
                // 如果类没有找到抛出ClassNotFoundException 没有父类加载
            }
            if (c == null) {
                // 如果仍然没有找到,然后调用findClass去寻找class
                long t1 = System.nanoTime();
                c = findClass(name);
                  这是定义的类装入器;记录数据;
                sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                sun.misc.PerfCounter.getFindClasses().increment();
            }
        }
        if (resolve) {
            resolveClass(c);
        }
        return c;
    }
}

为什么要使用双亲委派机制去加载类?

  • 避免对分同样字节码的加载

没必要保存相同的类对象class。不使用委托机制,则每个类加载一次Class文件,内存中会有多份class文件。使用委托机制,自定义classLoader开始逐层向上查询是否装载,如果有则不再装载。保证内存中只有一份class文件。

6、类的加载方式

  • 隐式加载:new
  • 显示加载:loadClass,forName等

类的装载过程

请添加图片描述

loadClass和forName的区别

  • Class.forName得到的 class 是已经初始化完成的(完成加载、链接、初始化)
  • Classloder.loadClass得到的 class 是还没有链接的(完成加载)
package com.lydms.IO;
public class Robot {
    static {
        System.out.println("Hello Robot");
    }
}

采用classLoader方式加载(未执行static方法)

public static void main(String[] args) throws ClassNotFoundException {
    ClassLoader classLoader = Robot.class.getClassLoader();
}

采用Class.forName( )方式加载(执行static中方法)

public static void main(String[] args) throws ClassNotFoundException {
    Class.forName("com.lydms.IO.Robot");
}

7、Java的内存模型

在程序执行的过程中,需要不断将内存的逻辑地址与物理地址进行映射,找到相关的指令以及数据去执行,java运行时面对着与其它进程完全相同的内存限制即受限于操作系统架构提供的可寻址地址空间,操作系统架构提供的可寻址地址空间由操作系统的位数决定,32位处理器提供了2^32的可寻址范围即4GB.

内核空间:内核是主要的操作系统程序和C运行时的空间,包含用于连接计算机硬件,调度程序,提供联网和虚拟内存等服务的逻辑和基于C的进程。

用户空间:用户空间是java进程实际运行时使用的内存空间,32位系统用户最多可以访问3GB,内核可以访问所有物理内存,而64位系统用户进程最大可以访问超过512gb,内核代码同样可以访问所有物理空间。

内存简介

请添加图片描述

  • 32位处理器:2^32的可寻址范围
  • 64位处理器:2^64的可寻址范围

地址空间的划分

  • 内核空间(主要操作系统程序和C运行位置)
  • 用户空间(Java程序运行位置)

请添加图片描述

Java内存模型(Runtime Data Area)

请添加图片描述

JVM内存模型—JDK8

请添加图片描述

程序计数器(Program Counter Register)

  • 当前线程所执行的字节码行号指示器(逻辑)。
  • 改变计数器的值来选取下一条需要执行的字节码指令。
  • 和线程是一对一的关系即“线程私有”。
  • 对Java方法计数,如果是Native方法则计数器值为 Undefined
  • 不会发生内存泄露。

Java虚拟机栈(Stack)

  • Java方法执行的内存模型
  • 包含多个栈针

请添加图片描述

局部变量表和操作数栈

  • 局部变量表:包含方法执行过程中的所有变量。
  • 操作数栈:入栈、出栈、复制、交换、产生消费变量。
public class ByteCodeSample{
    public static int add(int a, int b){
        int c=0;
        c = a + b;
        return c;
    }
}

javap 反编译后

请添加图片描述

执行 add(1,2)

请添加图片描述

0:iconst_0:0压入操作数栈,1/2放入局部变量表

  • 1: istore_2:将栈中元素弹出,放到局部变量表中2位置。
  • 2: iload_0:将局部变量中第0个元素,压入栈中。
  • 3: iload_1:将局部变量中第1个元素,压入栈中。
  • 4: iadd:将栈中0和1进行计算,并将结果压入栈顶。
  • 5: istore_2:将栈中元素弹出,放到局部变量2位置
  • 6: iload_2:将局部变量2中元素,压入栈中。
  • 7: ireturn:将栈中元素返回

递归为什么会引发 java.lang StackOverflow Error 异常

当线程执行一个方法时,就创建一个栈针,并将创建的栈针压入虚拟机栈中,当方法执行完毕时,将栈针出栈。一直自己调用自己,不能释放栈针,递归过深,栈帧数超过虚拟栈深度,抛出StackOverflow Error异常。

递归过深,栈帧数超出虚拟栈深度。

虚拟机栈过多会引发 java.lang.OutofMemory Error(内存溢出)异常

栈内存不需要通过GC回收,就能够自动释放内存。

本地方法栈(Native Method Stack)

与虚拟机栈相似,主要作用于标注了 native的方法

8、元空间(MetaSpace)与永久代(PermGen)的区别

元空间:JDK1.8后,类的元数据放在本地堆内存中,叫做元空间(MetaSpace)。这一块区域在JDK1.7以前属于永久代,元空间与永久代都是用来存储class的相关信息,包括class的method与field等,元空间与永久代都是方法区的实现,只是实现方法有所不同.所以说方法区只是JVM的规范,原先位于方法区的JVM常量池已被移动到堆中,并且在jdk8以后用元空间替代了永久代。

,

  • 元空间使用本地内存,而永久代使用的是JVM的内存。
  • 此异常不存在了: java.lang.OutOfMemoryError:PermGen space

MetaSpace相比 Permgen的优势

  • 字符串常量池存在永久代中,容易出现性能问题和内存溢出。
  • 类和方法的信息大小难易确定,给永久代的大小指定带来困难。
  • 永久代会为GC带来不必要的复杂性。
  • 方便 Hotspot与其他JVM如 Jrockit 的集成。

Java堆(Heap)

  • 对象实例的分配区域。
  • GC管理的主要区域。

java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建,此内存区域的唯一目的就是存放对象实例,所有的对象实例都在这里分配内存.也是GC管理的主要区域。

32位处理器java进程的内存布局:

请添加图片描述

现在收集器基本都采用分代收集算法,所以java堆还可以分为新生代和老年代:

请添加图片描述

8、Java内存模型之常考习题

JVM三大性能调优参数-Xms-Xmx-Xss的含义

  • -Xms:堆的初始值。
  • -Xmx:堆能达到的最大值。
  • -Xss:规定了每个线程虚拟机栈(堆栈)的大小
  • -Xmn10m:设置新生代大小为20m。

通常将-Xms与-Xmx写成一样的,避免内存抖动,不必再为扩展内存空间而消耗性能;

Java内存模型中堆和栈的区别->内存分配策略

程序运行时有三种内存分配策略,静态的,栈式的,堆式的。

  • 静态存储:编译时确定每个数据目标在运行时的存储空间需求。(静态存储是指在编译时能确定每个数据目标在运行时的存储空间需求,因而在编译时就能分配给它们固定的内存空间,这种程序分配策略要求代码中不能有可变数据集,以及嵌套,递归的结构出现)
  • 栈式存储:数据区需求在编译时未知,运行时模块入口前确定。(该程序可被动态的存储分配,程序对数据区的要求是编译时是完全未知的,运行时才能知道,但是规定在运行到数据模块时必须知道该程序所需内存的大小以分配其内存)
  • 堆式存储:编译时或运行时模块入口都无法确定,动态分配.

Java内存模型中堆和栈的区别

  • 联系:引用对象、数组时,栈里定义变量保存堆中目标的首地址

请添加图片描述

区别:

  • 管理方式:栈自动释放,堆需要GC。
  • 空间大小:栈比堆小。
  • 碎片相关:栈产生的碎片远小于堆。
  • 分配方式:栈支持静态和动态分配,而堆仅支持动态分配。
  • 效率:栈的效率比堆高。

元空间、堆、线程独占部分间的联系—内存角度

public class HelloWorld {
    private String name;


    public void getName() {
        System.out.println("Hello" + name);
    }


    public void setName(String name) {
        this.name = name;
    }


    public static void main(String[] args) {
        int a = 1;
        HelloWorld hw = new HelloWorld();
        hw.setName("Test");
        hw.getName();
    }
}

请添加图片描述

不同版本之间的intern( )方法的区别—JDK6 VS JDK6+

String s = new String( "a")
s .intern( );
  • JDK6:当调用 intern方法时,如果字符串常量池先前已创建出该字符串对象,则返回池中的该字符串的引用。否则,将此字符串对象添加到字符串常量池中,并且返回该字符串对象的引用。
  • JDK6+:当调用 intern方法时,如果字符串常量池先前已创建出该字符串对象,则返回池中的该字符串的引用。否则,如果该字符串对象已经存在于Java堆中,则将堆中对此对象的引用添加到字符串常量池中,并且返回该引用;如果堆中不存在,则在池中创建该字符串并返回其引用。

请添加图片描述

10、字符串常量池

JVM中的常量池从永久代中,移动到了堆中。

public class PermGenErrTest {
   public static void main(String[] args) {
       for (int i = 0; i < 1000; i++) {
//            将返回的随机字符串添加到字符串常量池中
           getRandomString(100000).intern();
       }
       System.out.println("Creat End");
   }


   //    返回指定长度的随机字符串
   private static String getRandomString(int length) {
//        字符串源
       String str = "asdfasdfiouwerwelsdfkjsafjiasfnsnfsdafsfs";
       Random random = new Random();
       StringBuffer sb = new StringBuffer();
       for (int i = 0; i < length; i++) {
           int number = random.nextInt(20);
           sb.append(str.charAt(number));
       }
       return sb.toString();
   }
}

设置永久代的大小

-XX: MaxPermSize=6M    永久代最大为6M
-XX: PermSize=6M        初始时永久代大小
-XX:MaxDirectMemorySize 可以设置java堆外内存的峰值

JDK6(报出异常—永久代内存溢出)

请添加图片描述

JDK7+(正常执行)

请添加图片描述

public class Test {
    public static void main(String[] args) {
//        存在堆中
        String s = new String("a");
//        想放到常量池中,但是其中已经存在,放失败
        s.intern();
//        常量池中
        String s2="a";
        System.out.println("s==s2: "+(s==s2));

//        拼接为"aa",在进行比较
        String s3 = new String("a") + new String("a");
        s3.intern();
        String s4="aa";
        System.out.println("s3==s4: "+(s3==s4));
    }
}

输出结果:
JDK6中:

s==s2: false
s3==s4: false

JDK6+中:

s==s2: false
s3==s4: true

解析:

是在常量池中创建"a’,再在堆中创建"a"的空间。也就是占用2份内存空间。

String s = new String("a");

在堆中创建出"aa",并将"aa"放置到常量池中

String s3 = new String("a") + new String("a");
s3.intern();

s==s2: false

String s = new String("a");在堆中创建内存空间,s指的是堆内存地址。
String s2="a";引用的是常量池中的地址。

s3==s4: true

JDK6:中副本,指向的是常量池和堆中
JDK6+:常量池中可以放置引用。
生成的s3值"aa",存在于堆中,将其引用放在常量池中。
s4创建的时候,查看常量池中有"aa"的引用(指向堆中),则使用该引用。则S3==S4(true)
堆中"aa",常量池中有"aa"的引用。

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

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

相关文章

0012-TIPS-pawnyable : Use-After-Free

原文 Linux Kernel PWN | 040203 Pawnyable之UAF https://pawnyable.cafe/linux-kernel/LK01/use_after_free.html 题目下载 漏洞代码 #include <linux/module.h> #include <linux/kernel.h> #include <linux/cdev.h> #include <linux/fs.h> #includ…

【踩坑】Windows11安装WSL2,然后装miniconda

Windows11安装WSL2 跟着官方文档一步步来就完事了&#xff0c;你要在vscode上用还是用docker都有教程微软WSL文档 遇到问题 Installing, this may take a few minutes… WslRegisterDistribution failed with error: 0x80370102 Please enable the Virtual Machine Platform W…

chatgpt赋能python:Python收费怎么办?

Python收费怎么办&#xff1f; Python是一门非常流行的编程语言&#xff0c;特别是在数据科学和机器学习领域中。许多人使用Python来编写自己的应用程序和脚本&#xff0c;但是有些人会对Python的收费问题感到困惑。本文将介绍Python的收费情况以及如何解决这个问题。 Python…

Shell - 02_shell的自定义变量

一、shell的自定义变量 1.定义变量&#xff1a;变量名变量值 如&#xff1a;num10 2.引用变量&#xff1a;$变量名 如&#xff1a;i$num 把变量 num 的值付给变量 i 3.显示变量&#xff1a;使用 echo 命令可以显示单个变量取值 如&#xff1a;echo $num 4.清除变量&…

高校学生公寓安全用电物联网平台的应用

摘要:本文针对高校学生公寓用电特点,从安全用电角度提出了一套集用电管理、计量、恶性负载智能识别控制、实时跟踪检测等功能于一体的数字化安全用电管理系统技术解决方案———学生公寓智能控电管理系统。 关键词:公寓恶性负载安全用电智能系统 0、引言 近年来,为了响应国家…

webpack编译打包

1.安装webpack npm install webpack webpack-cli --save-dev 2.添加命令 在package.json文件中添加启动命令 3.打包 webpack.config.js文件 通过配置文件构建&#xff1a;npx webpack --config webpack.config.js 4.文件结构 src:用于存放代码&#xff0c;一般入口为index.…

HQChart实战教程64-自定义分时图标题栏

HQChart实战教程64-自定义分时图标题栏 分时图标题栏步骤1. 替换分时图标题格式化输出函数2. 格式化输出函数说明HQChart插件源码地址完整的demo源码分时图标题栏 分时图标题栏显示的是当前十字光标所在位置的分钟信息,显示在分时图窗口顶部。一般会显示品种的名称,日期,时间…

android内部存储和外部存储

我们在开发Android应用的过程中&#xff0c;避免不了要用到数据持久化技术&#xff0c;所谓的数据持久化就是将RAM中的瞬时数据保存到ROM中&#xff0c;保证在App退出或者手机关机后数据不会丢失。我们常用的数据持久化的方式有文件存储&#xff0c;数据库存储&#xff0c;Shar…

动手实现条件随机场(下)

引言 本文基于PyTorch实现条件随机场&#xff0c;实现CRF层参考论文Neural Architectures for Named Entity Recognition中关于CRF层的描述。包含大量的图解和例子说明&#xff0c;看完一定能理解&#xff01; 论文地址&#xff1a; https://arxiv.org/pdf/1603.01360.pdf 也可…

chatgpt赋能python:Python搜索算法:如何提高你的搜索体验

Python 搜索算法&#xff1a;如何提高你的搜索体验 在当今信息爆炸的时代&#xff0c;搜索已成为许多人获取信息的主要途径。而 Python 的搜索算法&#xff0c;也在此背景下日渐受到重视。本篇文章将深入探讨 Python 搜索算法&#xff0c;介绍以及如何使用它来提高你的搜索体验…

SpringBoot整合模板引擎Thymeleaf(5)

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl 概述 在本节教程中&#xff0c;我们在之前案例的基础上详细介绍利用Thymeleaf实现国际化。 项目结构 依赖文件 请在pom.xml文件中添加如下依赖。 <?xml version"…

Android 9 蓝牙协议初始化

先讲一下Application类的使用 要使用自定义的Application&#xff0c;首先就是要自己新建一个Application的子类&#xff0c;然后把它的名字写在manifest文件里面的application标签里的android:name属性就行&#xff0c;如我的Application子类名字是BaseApplication&#xff0c…

java入门3(程序流程结构)

目录 大部分和C语言一样 顺序结构 选择结构 简单if语句 ​ 多重if结构 嵌套if结构 Switch选择结构 if和Switch嵌套 循环结构 while循环 do while 语句 for循环 break和continue break 中断指令&#xff0c;结束所在层的循环 continue:中断指令 中断本轮的循环&…

chatgpt赋能python:Python收发短信:简单可靠的解决方案

Python收发短信&#xff1a;简单可靠的解决方案 如果您需要向客户发送定期提醒或通知的短信&#xff0c;则 Python 是一种简单易用的解决方案。在本文中&#xff0c;我们将介绍如何使用 Python 发送和接收短信&#xff0c;并探讨一些流行的短信 API。 什么是短信 API&#xf…

深入分析vfio-user设备实现原理 —— Client侧

文章目录 前言数据结构protocolVFIOUserHdrvfio_user_commandVFIOUserHdr flags 设备模型VFIODeviceVFIODevIOVFIOContIO VFIOPCIDeviceVFIOKernPCIDeviceVFIOUserPCIDevice proxyVFIOUserMsgVFIOProxy 流程详解消息发松流程DMA映射流程 前言 数据结构 protocol VFIO User P…

「解析」YOLOv4模型小结

Paper Yolo v4: https://arxiv.org/abs/2004.10934 Scaled-YOLOv4: Scaling Cross Stage Partial Network Source code:https://github.com/AlexeyAB/darknet Bag of Freebies(BoF) 只增加训练成本&#xff0c;但是能显著提高精度&#xff0c;并不影响推理速度&#xff1b;数据…

Kubernetes使用Istio

Kubernetes使用Istio 1、基本概念 1.1、流量方向 南北流量&#xff08;NORTH-SOURTH-TRAFFIC&#xff09;&#xff1a;客户端到服务器之间通信的流量 东西流量(EAST-WEST-TRAFFIC)&#xff1a;指的是服务器和服务器之间的流量 1.2、Service Mesh 2、安装Istio 2.1、下载 …

【编译、链接、装载九】静态链接

【编译和链接九】静态链接 一、demo二、空间与地址分配1、相似段合并 三、即虚拟地址VMA&#xff08;Virtual Memory Address&#xff09;四、重定位1、add调用2、printf调用——同add2、shared 五、重定位表六、符号解析七、c相关问题1、重复代码消除2、全局构造与析构3、C与A…

从创建到维护:掌握package.json的最佳实践

文章目录 I. 介绍什么是package.jsonpackage.json的作用npm与package.json的关系 II. 创建package.jsonnpm init自动生成package.jsonpackage.json各个字段的含义 III. dependencies和devDependenciesdependencies和devDependencies的区别安装依赖包安装依赖包的版本更新依赖包…

Flink 学习十 FlinkSQL

Flink 学习十 Flink SQL 1. FlinkSQL 基础概念 flink sql 基于flink core ,使用sql 语义方便快捷的进行结构化数据处理的上层库; 类似理解sparksql 和sparkcore , hive和mapreduce 1.1 工作流程 整体架构和工作流程 数据流,绑定元数据 schema ,注册成catalog 中的表 table …