深入理解 JVM 之——Java 内存区域与溢出异常

news2025/4/7 20:38:28

更好的阅读体验 \huge{\color{red}{更好的阅读体验}} 更好的阅读体验

本篇为深入理解 Java 虚拟机第二章内容,推荐在学习前先掌握基础的 Linux 操作、编译原理、计算机组成原理等计算机基础以及扎实的 C/C++ 功底。

该系列的 GitHub 仓库:https://github.com/Doge2077/learn-jvm


运行时数据区域


Java 虚拟机在执行 Java 程序的过程中会把它所管理的内存划分为以下数据区域。

image-20230831150214981


程序计数器


程序计数器(Program Counter Register)是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。

Java 中,方法的执行可以分为两种情况:Java 方法和本地方法。Java 方法是用 Java 语言编写的方法,而本地方法是使用其他语言(如 CC++)编写的方法,通过 Java Native Interface(JNI)在 Java 程序中调用。

由于 Java 虚拟机的多线程是通过线程轮流切换、分配处理器执行时间的方式来实现,因此:

  • 每条线程都有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储。
  • 如果线程正在执行的是一个 Java 方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是本地(Native)方法,这个计数器值则应为空(Undefined)。

值得注意的是,在 《Java 虚拟机规范中》,计数器所在的内存区域是唯一一个没有规定任何 OutOfMemoryError 情况的区域。这意味着计数器不会因为内存不足而导致 OutOfMemoryError 异常。


Java 虚拟机栈


Java 虚拟机中的虚拟机栈(Java Virtual Machine Stack),它是线程私有的,其生命周期与线程相同。

虚拟机栈用于描述 Java 方法的执行过程,每个方法在执行时都会创建一个栈帧,用于存储局部变量表、操作数栈、动态连接和方法出口等信息。栈帧在虚拟机栈中入栈和出栈,对应着方法的调用和执行过程

Java 虚拟机中,栈内存通常指的是虚拟机栈,大多数情况下指的是虚拟机栈中的局部变量表部分。

局部变量表用于存放编译期可知的各种 Java 虚拟机基本数据类型、对象引用和 returnAddress 类型。局部变量表的存储空间以局部变量槽(Slot)表示,其中 longdouble 类型的数据占用两个变量槽,其他数据类型占用一个变量槽。

HotSpot 虚拟机的栈容量是不可以动态扩展的,以前的 Classic 虚拟机倒是可以。所以在 HotSpot 虚拟机上是不会由于虚拟机栈无法扩展而导致 OutOfMemoryError 异常——只要线程申请栈空间成功了就不会有 OOM,但是如果申请时就失败,仍然是会出现 OOM 异常的

一般情况下,局部变量表所需的内存空间在编译期间确定,并在方法运行期间不会改变大小(变量槽的数量)。


本地方法栈


本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用相似,其区别只是虚拟机栈为虚拟机执行 Java 方法(也就是字节
码)服务,而本地方法栈则是为虚拟机使用到的本地(Native)方法服务。

《Java虚拟机规范》对本地方法栈中方法使用的语言、使用方式与数据结构并没有任何强制规定,因此具体的虚拟机可以根据需要自由实
现它。

对于HotSpot虚拟机,它将本地方法栈(Native Method Stack)和虚拟机栈(Java Virtual Machine Stack)合二为一,这意味着它可以在同一个栈中管理 Java 方法和本地方法的执行。


Java 堆


Java 堆(Java Heap)是虚拟机所管理的内存中最大的一块,被所有线程共享的一块内存区域,在虚拟机启动时创建。

  • 此内存区域的唯一目的就是存放对象实例,所有的对象实例都在这里分配内存。
  • 该内存区域受到垃圾收集器管理,也被称为“GC”堆(Garbage Collected Heap)。
  • Java 堆可以处于物理上不连续的内存空间中,但在逻辑上它应该被视为连续的。
  • Java 堆既可以被实现成固定大小的,也可以是可扩展的(通过参数 -Xmx-Xms 设定)。

如果在 Java 堆中没有内存完成实例分配,并且堆也无法再扩展时,Java 虚拟机将会抛出 OutOfMemoryError 异常。


方法区


方法区(Method Area)与Java堆一样,是各个线程共享的内存区域:

  • 用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。
  • 方法区和 Java 堆一样不需要连续的内存和可以选择固定大小或者可扩展外,甚至还可以选择不实现垃圾收集。

早期 HotSpot 虚拟机设计团队把收集器的分代设计扩展至方法区,因此方法区也被成为“永久代”,但只是使用永久代来实现方法区而已,这种设计导致了 Java 应用更容易遇到内存溢出的问题,在JDK 6的时候HotSpot开发团队就有放弃永久代,逐步改为采用本地内存(Native Memory)来实现方法区的计划了,到了JDK 7的HotSpot,已经把原本放在永久代的字符串常量池、静
态变量等移出,而到了JDK8,终于完全废弃了永久代的概念,改用与 JRockitJ9 一样在本地内存中实现的元空间(Meta-space)来代替。

如果方法区无法满足新的内存分配需求时,将抛出 OutOfMemoryError 异常。


运行时常量池


运行时常量池(Runtime Constant Pool)是方法区的一部分:

  • Class 文件中包含的常量池表(Constant Pool Table),用于存放编译期生成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。
  • 并非预置入 Class 文件中常量池的内容才能进入方法区运行时常量池,运行期间也可以将新的常量放入池,如 String 类的 intern() 方法。

除了String类的intern()方法之外,还有其他方法可以将常量放入运行时常量池。以下是一些常见的方法:

  1. Class.forName(String className):在使用反射加载类时,如果指定的类名在运行时常量池中不存在,会将该类名添加到运行时常量池中。
  2. String类的valueOf(Object obj)方法:当调用String.valueOf(Object obj)方法时,如果运行时常量池中不存在对应的字符串,会将该字符串添加到运行时常量池中。
  3. StringBuilderStringBuffer类的toString()方法:当调用StringBuilderStringBuffer对象的toString()方法时,如果返回的字符串在运行时常量池中不存在,会将该字符串添加到运行时常量池中。

运行时常量池是方法区的一部分,自然受到方法区内存的限制,当常量池无法再申请到内存时会抛出 OutOfMemoryError 异常。


直接内存


直接内存(Direct Memory)并不是虚拟机运行时数据区的一部分,也不是《Java虚拟机规范》中定义的内存区域。

本机直接内存的分配不会受到 Java 堆大小的限制,但受到本机总内存(包括物理内存、SWAP分区或者分页文件)大小以及处理器寻址空间的限制。

配置虚拟机参数时,要根据实际内存去设置 -Xmx 等参数信息,忽略掉直接内存,会使得各个内存区域总和大于物理内存限制(包括物理的和操作系统级的限制),从而导致动态扩展时出现 OutOfMemoryError 异常。


HotSpot 虚拟机对象


对象的创建


Java 虚拟机遇到一条字节码 new 指令时:

  • 首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。若没有则执行相应的类加载过程。
  • 在类加载检查通过后,虚拟机为对象进行内存划分:
    • 指针碰撞(Bump The Pointer)式划分:对于绝对规整的空间,通过指针划分使用和空闲的空间,划分空间的过程等同于指针向空闲空间方向挪动一段与对象大小相等的距离
    • 空闲列表(Free List)式划分:对于不规整的空间,已使用的内存和空闲内存相互交错,则虚拟机必须维护一个列表用于记录可用的内存区域,划分空间的过程等同于从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录
  • 空间分配完成后,还要对对象进行必要的设置:
    • 将该对象的抽象类元数据信息、哈希码等存放在对象的对象头(Object Header)之中
    • 根据虚拟机当前运行状态的不同,如是否启用偏向锁等,对象头会有不同的设置方式。

在上面工作都完成之后,从虚拟机的视角来看,一个新的对象已经产生了。之后 Java 程序再调用其中 Class 文件的 <init>() 方法对该对象进行初始化。

注意

  • 如果在执行 new 指令时检查到该类已经被加载,虚拟机会获取到该类的运行时常量池中的直接引用,然后继续执行后续操作,如方法调用等。
  • 实际上的内存划分更为复杂,在并发情况下需要考虑到线程安全,通常采用 CAS 配上失败重试的方式保证更新操作的原子性,或者把内存分配的动作按照线程划分在不同的空间之中进行。
  • Java 编译器会在遇到 new 关键字的地方同时生成这两条字节码指令(但如果直接通过其他方式产生的则不一定如此),new 指令之后会接着执行 <init>() 方法。

对象的内存布局


HotSpot 虚拟机里,对象在堆内存中的存储布局可以划分为三个部分:

  • 对象头(Header):主要存储两类信息,第一类存储对象自身的运行时数据,如哈希码(Hash Code)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等;第二类存储类型指针,指向它的类型元数据,用于确定是哪个类的实例。
  • 实例数据(Instance Data):对象真正存储的有效信息,即程序员定义的各种类型的字段内容,无论是从父类继承下来的,还是在子类中定义的字段都必须记录起来。
  • 对齐填充(Padding):这部分可有可无,起占位符的作用。

对象的访问定位


Java 程序会通过栈上的 reference 数据来操作堆上的具体对象,主流访问方式有以下两种:

  • 句柄访问:Java 堆中将可能会划分出一块内存来作为句柄池,reference 中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自具体的地址信息。
  • 直接指针访问:Java 堆中对象的内存布局就必须考虑如何放置访问类型数据的相关信息,reference中存储的直接就是对象地址,如果只是访问对象本身的话,就不需要多一次间接访问的开销。

句柄访问在对象被移动(垃圾收集时移动对象是非常普遍的行为)时只会改变句柄中的实例数据指针,而 reference 本身不需要被修改。而指针访问最大的好处就是速度更快,节省了一次指针定位的时间开销。


实战 :OOM 异常


Java 堆异常


public class HeapOOM {
    static class OOMObject {
        Long num[] = new Long[10000000];
    }
    public static void main(String[] args) {
        List<OOMObject> list = new ArrayList<OOMObject>();
        while (true) {
            list.add(new OOMObject());
            System.out.println(list.size());
        }
    }
}

Java 堆用于储存对象实例,我们只要不断地创建对象并保证不被回收,最终数量一定会超出内存限制。

运行后报错:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

java.lang.OutOfMemoryError: Java heap space 表明了该异常是 Java 堆空间异常。


虚拟机栈和本地方法栈溢出


由于 HotSpot 虚拟机中并不区分虚拟机栈和本地方法栈,因此对于 HotSpot 来说,-Xoss 参数(设置本地方法栈大小)虽然存在,但实际上是没有任何效果的,栈容量只能由 -Xss 参数来设定。

关于虚拟机栈和本地方法栈,在《Java虚拟机规范》中描述了两种异常:

  • 如果线程请求的栈深度大于虚拟机栈所允许的最大深度,将递归地抛出的 StackOverflowError 异常。
  • 如果虚拟机的栈内存允许动态扩展,当扩展栈容量无法申请到足够的内存时,将抛出 OutOfMemoryError 异常。

对于第一种异常,可以设置 -Xss 参数调整栈容量到出现异常的值,也可以使用如下代码:

public class JavaVMStackSOF {
    private int stackLength = 1;
    public void stackLeak() {
        stackLength ++;
        stackLeak();
    }
    public static void main(String[] args) throws Throwable {
        JavaVMStackSOF oom = new JavaVMStackSOF();
        try {
            oom.stackLeak();
        } catch (Throwable e) {
            System.out.println("stack length:" + oom.stackLength);
            throw e;
        }
    }
}

递归调用的方法 stackLeak(),当虚拟机栈空间不足以容纳新的栈帧时报错如下:

stack length:23360
Exception in thread "main" java.lang.StackOverflowError

每次递归调用都会在虚拟机栈中申请空间,直到达到最大深度。

对于第二种异常,我们要尽可能地多占局部变量表空间,唯一能做的就是定义大量的变量来实现:

public class JavaVMStackSOF {
    private static int stackLength = 0;

    public static void test() {
        long unused1, unused2, unused3, unused4, unused5, unused6, unused7, unused8, unused9, unused10,
                unused11, unused12, unused13, unused14, unused15, unused16, unused17, unused18, unused19, unused20,
                unused21, unused22, unused23, unused24, unused25, unused26, unused27, unused28, unused29, unused30,
                unused31, unused32, unused33, unused34, unused35, unused36, unused37, unused38, unused39, unused40,
                unused41, unused42, unused43, unused44, unused45, unused46, unused47, unused48, unused49, unused50,
                unused51, unused52, unused53, unused54, unused55, unused56, unused57, unused58, unused59, unused60,
                unused61, unused62, unused63, unused64, unused65, unused66, unused67, unused68, unused69, unused70,
                unused71, unused72, unused73, unused74, unused75, unused76, unused77, unused78, unused79, unused80,
                unused81, unused82, unused83, unused84, unused85, unused86, unused87, unused88, unused89, unused90,
                unused91, unused92, unused93, unused94, unused95, unused96, unused97, unused98, unused99, unused100,
                unused101, unused102, unused103, unused104, unused105, unused106, unused107, unused108, unused109, unused110,
                unused111, unused112, unused113, unused114, unused115, unused116, unused117, unused118, unused119, unused120,
                unused121, unused122, unused123, unused124, unused125, unused126, unused127, unused128, unused129, unused130,
                unused131, unused132, unused133, unused134, unused135, unused136, unused137, unused138, unused139, unused140,
                unused141, unused142, unused143, unused144, unused145, unused146, unused147, unused148, unused149, unused150,
                unused151, unused152, unused153, unused154, unused155, unused156, unused157, unused158, unused159, unused160,
                unused161, unused162, unused163, unused164, unused165, unused166, unused167, unused168, unused169, unused170,
                unused171, unused172, unused173, unused174, unused175, unused176, unused177, unused178, unused179, unused180,
                unused181, unused182, unused183, unused184, unused185, unused186, unused187, unused188, unused189, unused190,
                unused191, unused192, unused193, unused194, unused195, unused196, unused197, unused198, unused199, unused200;

        unused1 = unused2 = unused3 = unused4 = unused5 = unused6 = unused7 = unused8 = unused9 = unused10 =
                unused11 = unused12 = unused13 = unused14 = unused15 = unused16 = unused17 = unused18 = unused19 = unused20
                        = unused21 = unused22 = unused23 = unused24 = unused25 = unused26 = unused27 = unused28 = unused29 = unused30
                        = unused31 = unused32 = unused33 = unused34 = unused35 = unused36 = unused37 = unused38 = unused39 = unused40
                        = unused41 = unused42 = unused43 = unused44 = unused45 = unused46 = unused47 = unused48 = unused49 = unused50
                        = unused51 = unused52 = unused53 = unused54 = unused55 = unused56 = unused57 = unused58 = unused59 = unused60
                        = unused61 = unused62 = unused63 = unused64 = unused65 = unused66 = unused67 = unused68 = unused69 = unused70
                        = unused71 = unused72 = unused73 = unused74 = unused75 = unused76 = unused77 = unused78 = unused79 = unused80
                        = unused81 = unused82 = unused83 = unused84 = unused85 = unused86 = unused87 = unused88 = unused89 = unused90
                        = unused91 = unused92 = unused93 = unused94 = unused95 = unused96 = unused97 = unused98 = unused99 = unused100
                        = unused101 = unused102 = unused103 = unused104 = unused105 = unused106 = unused107 = unused108 = unused109 = unused110
                        = unused111 = unused112 = unused113 = unused114 = unused115 = unused116 = unused117 = unused118 = unused119 = unused120
                        = unused121 = unused122 = unused123 = unused124 = unused125 = unused126 = unused127 = unused128 = unused129 = unused130
                        = unused131 = unused132 = unused133 = unused134 = unused135 = unused136 = unused137 = unused138 = unused139 = unused140
                        = unused141 = unused142 = unused143 = unused144 = unused145 = unused146 = unused147 = unused148 = unused149 = unused150
                        = unused151 = unused152 = unused153 = unused154 = unused155 = unused156 = unused157 = unused158 = unused159 = unused160
                        = unused161 = unused162 = unused163 = unused164 = unused165 = unused166 = unused167 = unused168 = unused169 = unused170
                        = unused171 = unused172 = unused173 = unused174 = unused175 = unused176 = unused177 = unused178 = unused179 = unused180
                        = unused181 = unused182 = unused183 = unused184 = unused185 = unused186 = unused187 = unused188 = unused189 = unused190
                        = unused191 = unused192 = unused193 = unused194 = unused195 = unused196 = unused197 = unused198 = unused199 = unused200
                        = 1145141919810L;
        stackLength++;
        test();
    }

    public static void main(String[] args) {
        try {
            test();
        } catch (Error e) {
            System.out.println("stack length:" + stackLength);
            throw e;
        }
    }
}

运行结果如下:

stack length:306
Exception in thread "main" java.lang.StackOverflowError

可以看到结果并不是我们想要的 OutOfMemoryError 异常。

这是因为 HotSpot 虚拟机的栈是不可动态扩展的,所以在 HotSpot 虚拟机上不会由于虚拟机栈无法扩展而导致 OutOfMemoryError 异常,这点我们在最初章节已经提到过了。


方法区和运行时常量池溢出


运行时常量池是方法区的一部分,所以这两个区域的溢出测试可以放到一起进行。

前面曾经提到 HotSpotJDK7开始逐步“去永久代”的计划,并在 JDK8 中完全使用元空间来代替永久代,我们可以使用如下代码来进行测试:

public class RuntimeConstantPoolOOM {
    public static void main(String[] args) {
        Set<String> set = new HashSet<String>();
        int i = 0;
        while (true) {
            set.add(String.valueOf(i ++).intern());
        }
    }
}

执行 javac RuntimeConstantPoolOOM.java 进行编译,再通过 -XX:PermSize -XX:MaxPermSize 参数设置永久代大小,接着执行:

java -XX:PermSize=6M -XX:MaxPermSize=6M RuntimeConstantPoolOOM

虚拟机报错如下:

Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=6M; support was removed in 8.0
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=6M; support was removed in 8.0

提示我们在 JDK8 已经将该参数移除了,如果使用 JDK7 及之前的版本运行,应该会出现如下结果:

Exception in thread "main" java.lang.OutOfMemoryError: PermGen space

而我们使用的高版本则需限制 -Xmx 参数来调整(自 JDK7 起,原本存放在永久代的字符串常量池被移至Java堆):

java -Xmx6m RuntimeConstantPoolOOM

运行后出现如下结果:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

本机直接内存溢出


直接内存(Direct Memory)的容量大小可通过 -XX:MaxDirectMemorySize 参数来指定,如果不去指定,则默认与 Java 堆最大值(由 -Xmx 指定)一致。

我们使用如下代码进行测试:

public class DirectMemoryOOM {
    private static final int _1MB = 1024 * 1024;
    public static void main(String[] args) throws Exception {
        Field unsafeField = Unsafe.class.getDeclaredFields()[0];
        unsafeField.setAccessible(true);
        Unsafe unsafe = (Unsafe) unsafeField.get(null);
        while (true) {
            unsafe.allocateMemory(_1MB);
        }
    }
}

在编译后,我们设置执行参数如下:

java -Xmx20M -XX:MaxDirectMemorySize=10M DirectMemoryOOM

运行后结果如下:

Exception in thread "main" java.lang.OutOfMemoryError  

这是由于在上述代码的每次循环中,unsafe.allocateMemory(_1MB) 会调用 Unsafe 类的 allocateMemory 方法来分配 1MB 的直接内存空间,最终导致直接内存溢出。


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

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

相关文章

LVS 实现四层负载均衡项目实战--DR模式(直接路由Direct Routing)

一、原理 负载均衡器和RS都使用同一个IP对外服务&#xff61;但只有DB对ARP请求进行响应,所有RS对本身这个IP的ARP请求保持静默&#xff61;也就是说,网关会把对这个服务IP的请求全部定向给DB,而DB收到数据包后根据调度算法,找出对应的RS,把目的MAC地址改为RS的MAC&#xff08…

MacOS 为指定应用添加指定权限(浏览器无法使用摄像头、麦克风终极解决方案)

起因&#xff1a;需要浏览器在线做一些测评&#xff0c;但我的 Chrome 没有摄像头/麦克风权限&#xff0c;并且在设置中是没有手动添加按钮的。 我尝试了重装软件&#xff0c;更新系统&#xff08;上面的 13.5 就是这么来的&#xff0c;我本来都半年懒得更新系统了&#xff09…

Tomcat安装及环境配置

一、首先确认自己是否已经安装JDK WinR打开运行&#xff0c;输入cmd回车&#xff0c;在DOS窗口中输入java 出现这些说明已经安装了&#xff0c;然后就是查看自己的版本 然后输入java -version 可以看到版本是1.8的 如果没有配置java环境变量&#xff0c;打开系统设置&#…

Linux安装JenkinsCLI

项目简介安装目录 mkdir -p /opt/jenkinscli && cd /opt/jenkinscli JenkinsCLI下载 wget http://<your-jenkins-server>/jnlpJars/jenkins-cli.jar # <your-jenkins-server> 替换为你的 Jenkins 服务器地址 JenkinsCLI授权 Dashboard-->Configure Glob…

渣土车识别监测 渣土车未盖篷布识别抓拍算法

渣土车识别监测 渣土车未盖篷布识别抓拍算法通过yolov7深度学习训练模型框架&#xff0c;渣土车识别监测 渣土车未盖篷布识别抓拍算法在指定区域内实时监测渣土车的进出状况以及对渣土车未盖篷布违规的抓拍和预警。YOLOv7 的策略是使用组卷积来扩展计算块的通道和基数。研究者将…

交叉导轨具有那些方面的优势?

交叉导轨和直线导轨这两种导轨经常被拿出来对比&#xff0c;从结构上来看&#xff0c;交叉导轨是分体结构&#xff0c;组装起来相对于直线导轨比较繁琐&#xff1b;从功能上来看&#xff0c;交叉导轨适合于短行程&#xff0c;高频率、高精度的场合。直线导轨可以做到6000mm单支…

Paimon+StarRocks 湖仓一体数据分析方案

摘要&#xff1a;本文整理自阿里云高级开发工程师曾庆栋&#xff08;曦乐&#xff09;在 Streaming Lakehouse Meetup 的分享。内容主要分为四个部分&#xff1a; 传统数据仓库分析实现方案简介PaimonStarRocks 构建湖仓一体数据分析实现方案StarRocks 与 Paimon 结合的使用方式…

从零开始,掌握C语言中的数据类型

数据类型 1. 前言2. 预备知识2.1 打印整数2.2 计算机中的单位 3. C语言有哪些数据类型呢&#xff1f;3.1 内置类型和自定义类型 4. 每种类型的大小是多少&#xff1f;5. 为什么有这么多数据类型呢&#xff1f;6. 这么多类型应该如何使用呢&#xff1f;6.1 一个小知识 1. 前言 …

Redis功能实战篇之Session共享

1.使用redis共享session来实现用户登录以及token刷新 当用户请求我们的nginx服务器&#xff0c;nginx基于七层模型走的事HTTP协议&#xff0c;可以实现基于Lua直接绕开tomcat访问redis&#xff0c;也可以作为静态资源服务器&#xff0c;轻松扛下上万并发&#xff0c; 负载均衡…

【VR】Network Manager HUD

&#x1f4a6;本专栏是我关于VR开发的笔记 &#x1f236;本篇是——Network Manager HUD Network Manager HUD组件 简介基础知识 简介 网络管理器 HUD是一种快速启动工具&#xff0c;可帮助您立即开始构建多人游戏&#xff0c;而无需首先构建用于游戏创建/连接/加入的用户界面…

云原生Kubernetes:二进制部署K8S单Master架构(一)

目录 一、理论 1.K8S单Master架构 2. etcd 集群 3.flannel网络 4.K8S单Master架构环境部署 5.部署 etcd 集群 6.部署 docker 引擎 7.flannel网络配置 二、实验 1.二进制部署K8S单Master架构 2. 环境部署 3.部署 etcd 集群 4.部署 docker 引擎 5.flannel网络配置…

Ramp 有点意思的题目

粗一看都不知道这个要干什么&#xff0c;这 B 装得不错。 IyEvdXNyL2Jpbi9lbnYgcHl0aG9uMwoKJycnCktlZXAgdXMgb3V0IG9mIGdvb2dsZSBzZWFyY2ggcmVzdWx0cy4uCgokIG9kIC1kIC9kZXYvdXJhbmRvbSB8IGhlYWQKMDAwMDAwMCAgICAgNjAyMTUgICAyODc3OCAgIDI5MjI3ICAgMjg1NDggICA2MjY4NiAgIDQ1MT…

浏览器端vscode docker搭建(附带python环境)

dockerfile from centos:7 #安装python环境 run yum -y install wget openssl-devel bzip2-devel expat-devel gdbm-devel readline-devel zlib-devel libffi-devel gcc make run wget https://www.python.org/ftp/python/3.9.0/Python-3.9.0.tgz run tar -xvf Python-3.9.…

六、编辑器vim编辑器的使用

1、编辑器 (1)编辑器就是一款软件。 (2)作用就是用来编辑文件&#xff0c;譬如编辑文字、编写代码。 (3)Windows中常用的编辑器&#xff0c;有自带的有记事本(notepad)&#xff0c;比较好用的notepad、VSCode等。 (4)Linux中常用的编辑器&#xff0c;自带的最古老的vi&…

中文完形填空

本文通过ChnSentiCorp数据集介绍了完型填空任务过程&#xff0c;主要使用预训练语言模型bert-base-chinese直接在测试集上进行测试&#xff0c;也简要介绍了模型训练流程&#xff0c;不过最后没有保存训练好的模型。 一.完形填空 完形填空应该大家都比较熟悉&#xff0c;就是把…

文件上传漏洞-upload靶场5-12关

文件上传漏洞-upload靶场5-12关通关笔记&#xff08;windows环境漏洞&#xff09; 简介 ​ 在前两篇文章中&#xff0c;已经说了分析上传漏的思路&#xff0c;在本篇文章中&#xff0c;将带领大家熟悉winodws系统存在的一些上传漏洞。 upload 第五关 &#xff08;大小写绕过…

如何用VMware虚拟机连上Xshell

目录 前言废话1.1设置虚拟机设置1.2 设置虚拟网络编辑器方法一&#xff1a;方法二&#xff1a; 1.3 配置静态IP地址1.4 Xshell连接虚拟机2.1 解决可能出现的一些问题2.1.1 虚拟机Ping不通网络2.1.2 我可以Ping通百度了&#xff0c;但是宿主机和虚拟机互相Ping不通。2.1.3 更离谱…

【8 排序】简单选择排序。

顺序表&#xff1a; void Swap(int &a,int &b){int temp;tempa;ab;btemp; } void SelectSort(int A[],int n){int min,i,j;for(i0;i<n-1;i){mini;for(ji1;j<n;j)if(A[j]<A[min])minj;if(min!i)Swap(A[i],A[min]);} } 单链表&#xff1a; void SelectSort…

【leetcode 力扣刷题】数学题之除法:哈希表解决商的循环节➕快速乘求解商

两道和除法相关的力扣题目 166. 分数到小数29. 两数相除快速乘解法一&#xff1a;快速乘变种解法二&#xff1a; 二分查找 快速乘 166. 分数到小数 题目链接&#xff1a;166. 分数到小数 题目内容&#xff1a; 题目是要求我们把一个分数变成一个小数&#xff0c;并以字符串的…

go锁-waitgroup

如果被等待的协程没了&#xff0c;直接返回 否则&#xff0c;waiter加一&#xff0c;陷入sema add counter 被等待协程没做完&#xff0c;或者没人在等待&#xff0c;返回 被等待协程都做完&#xff0c;且有人在等待&#xff0c;唤醒所有sema中的协程 WaitGroup实现了一组协程…