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

更好的阅读体验 \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.rhkb.cn/news/116535.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Power View

界面 切换可视化效果 对于已经上传到透视表的数据&#xff0c;选择power view&#xff0c;形成表格后。

国标视频云服务EasyGBS国标视频平台迁移服务器后无法启动的问题解决方法

国标视频云服务EasyGBS支持设备/平台通过国标GB28181协议注册接入&#xff0c;并能实现视频的实时监控直播、录像、检索与回看、语音对讲、云存储、告警、平台级联等功能。平台部署简单、可拓展性强&#xff0c;支持将接入的视频流进行全终端、全平台分发&#xff0c;分发的视频…

RT-Thread 线程管理(二)

系统线程 系统线程是指由系统创建的线程&#xff0c;用户线程是由用户程序调用线程管理接口创建的线程&#xff0c;在 RT-Thread 内核中的系统线程有空闲线程和主线程。 空闲线程 空闲线程&#xff08;idle&#xff09;是系统创建的最低优先级的线程&#xff0c;线程状态永远…

【MySQL】基础语法总结

MySQL 基础语句 一、DDL 数据库定义语言 1.1CREATE 创建 1.1.1 创建数据库 语法结构 CREATE DATABASE database_name;示例 CREATE DATABASE demo;1.1.2 创建表 语法结构 CREATE TABLE 表名 (列1 数据类型,列2 数据类型,... );示例 CREATE TABLE new_user (id INT PRIMARY KE…

JVM解密: 解构类加载与GC垃圾回收机制

文章目录 一. JVM内存划分二. 类加载机制1. 类加载过程2. 双亲委派模型 三. GC垃圾回收机制1. 找到需要回收的内存1.1 哪些内存需要回收&#xff1f;1.2 基于引用计数找垃圾(Java不采取该方案)1.3 基于可达性分析找垃圾(Java采取方案) 2. 垃圾回收算法2.1 标记-清除算法2.2 标记…

云服务器利用Docker搭建sqli-labs靶场环境

一、安装宝塔面板 使用xshell、electerm、SecureCRT等远程终端连接登陆上云服务器&#xff0c;在Linux宝塔面板使用脚本安装 安装后&#xff0c;如下图&#xff1a;按照提示&#xff0c;在云服务器防火墙/安全组放行Linux宝塔面板的端口 在浏览器打开上述网址&#xff0c;登…

基于微信小程序的汽车租赁系统的设计与实现ljx7y

汽车租赁系统&#xff0c;主要包括管理员、用户二个权限角色&#xff0c;对于用户角色不同&#xff0c;所使用的功能模块相应不同。本文从管理员、用户的功能要求出发&#xff0c;汽车租赁系统系统中的功能模块主要是实现管理员后端&#xff1b;首页、个人中心、汽车品牌管理、…

QEMU 仿真RISC-V freeRTOS 程序

1. 安裝RISC-V 仿真環境 --QEMU 安裝包下載地址: https://www.qemu.org/ 安裝命令及安裝成功效果如下所示, target-list 設定爲riscv32-softmmu, $ cat ~/project/qemu-8.0.4/install.sh sudo apt-get install libglib2.0-dev sudo apt-get install libpixman-1-dev ./co…

SpringBoot整合websockt实现消息对话

文章目录 前言websockt什么是websockt&#xff1f;websockt和Socket区别代码部分实战应用 前言 websockt 什么是websockt&#xff1f; WebSocket是一种在Web应用程序中实现实时双向通信的技术。Web应用程序通常是基于HTTP协议的&#xff0c;HTTP是一种请求/响应式的协议&…

Flutter开发- iOS 问题CocoaPods not installed or not in valid state

解决问题方案&#xff1a; 1、先检查本机CocoaPods是否安装&#xff0c;通过gem list 查看是否安装 打开终端&#xff0c;执行gem list&#xff0c;出现图中的数据即为已安装。未安装看第4 步 2、已经安装了CocoaPods&#xff0c;还出现了图中的提示&#xff0c;你可能已经猜…

C语言——多文件编程

多文件编程 把函数声明放在头文件xxx.h中&#xff0c;在主函数中包含相应头文件在头文件对应的xxx.c中实现xxx.h声明的函数 防止头文件重复包含 当一个项目比较大时&#xff0c;往往都是分文件&#xff0c;这时候有可能不小心把同一个头文件 include 多次&#xff0c;或者头…

个微API接口开发

请求URL&#xff1a; http://域名地址/sendText 请求方式&#xff1a; POST 请求头Headers&#xff1a; Content-Type&#xff1a;application/jsonAuthorization&#xff1a;login接口返回 参数&#xff1a; 参数名必选类型说明wId是string登录实例标识wcId是string接收…

小兔鲜儿 - 地址模块

目录 小兔鲜儿 - 地址模块 准备工作​ 静态结构​ 地址管理页​ 地址表单页​ 动态设置标题​ 新建地址页​ 接口封装​ 参考代码​ 地址管理页​ 接口调用​ 参考代码​ 修改地址页​ 数据回显​ 更新地址​ 表单校验​ 操作步骤​ 删除地址​ 侧滑组件用法…

蓝桥杯 2240. 买钢笔和铅笔的方案数c++解法

最近才回学校。在家学习的计划不翼而飞。但是回到学校了&#xff0c;还是没有找回状态。 现在是大三了&#xff0c;之前和同学聊天&#xff0c;说才大三无论是干什么&#xff0c;考研&#xff0c;找工作&#xff0c;考公&#xff0c;考证书 还都是来的及的。 但是心里面…

Systrace分析App性能学习笔记

学习Gracker Systrace系列文章&#xff0c;总结使用Systrace分析App性能的方法。推荐想通过Systrace学习Framework的同学&#xff0c;去看原文。 文章目录 概述Systrace使用流程Systrace 文件生成图形方式(不推荐)命令行方式 Systrace分析快捷键使用帧状态线程状态查看线程唤醒…

svn软连接和文件忽略

软连接 1)TortoiseSVN->Properties->New->Externals->New 2)填入软连接信息 Local path: 写下软连接后的文件夹的名字 URL: 想要软连接的牡蛎->TortoiseSVN->Repo-browser 复制下填入 文件忽略 以空格隔开就行

关闭jenkins插件提醒信息

jenkins提醒信息和安全警告可以帮助我们了解插件或者jenkins的更新情况&#xff0c;但是有些插件是已经不维护了&#xff0c;提醒却一直存在&#xff0c;看着糟心&#xff0c;就像下面的提示 1、关闭插件提醒 找到如下位置&#xff1a;系统管理-系统配置-管理监控配置 打开管…

图解 STP

网络环路 现在我们的生活已经离不开网络&#xff0c;如果我家断网&#xff0c;我会抱怨这什么破网络&#xff0c;影响到我刷抖音、打游戏&#xff1b;如果公司断网&#xff0c;那老板估计会骂娘&#xff0c;因为会影响到公司正常运转&#xff0c;直接造成经济损失。网络通信中&…

强大的处理器和接口支持BL304ARM控制器

在智慧医疗领域&#xff0c;BL304可以用于实现医疗设备的智能化、远程监控和数据交换。在智慧电力领域&#xff0c;BL304可以帮助实现电网的智能化管理&#xff0c;提升电力供应的效率。在智慧安防领域&#xff0c;BL304可以实现智能监控、智能门锁等应用&#xff0c;保障安全。…

【项目设计】高并发内存池(Concurrent Memory Pool)

目录 1️⃣项目介绍 &#x1f359;项目概述 &#x1f359;知识储备 2️⃣内存池介绍 &#x1f359;池化技术 &#x1f359;内存池 &#x1f359;内存池主要解决的问题 &#x1f365;内碎片 &#x1f365;外碎片 &#x1f359;malloc 3️⃣ 定长内存池设计 4️⃣ 项…