【JVM】JVM内存模型与操作系统内存模型(一)
JVM内存模型与操作系统内存模型
Java进程在操作系统内存中的结构
JVM内存模型
可以这样理解:JVM内存模型其实就是JVM在启动的时候从操作系统内存中要了一块大内存,然后将这个大内存分成五个区域:方法区、堆区、虚拟机栈、本地方法栈、本地方法栈、程序计数器.其实叫JVM运行时区域更合适。但是要区分JVM内存模型与JMM(Java Memory Model)
InstanceKlass:类的元信息(方法区)
InstanceMirrorKlass:镜像类Class对象(堆区)
四个名词:
class文件:即硬盘上的.class文件
class content:类加载器将硬盘上的.class文件读入内存中的那一块内存区域
Class对象:
Class<?> clazz = Test.class
对象:
Test obj = new Test();
方法区
方法区是虚拟机的一种规范
不同版本虚拟机堆方法区的具体实现
永久代(1.8之前是在堆区)
元空间(1.8之后,在直接内存上)
- 1.永久代的缺点?
放在堆上,很难触犯类的卸载机制
1.1 Class对象没有被使用
1.2 被三大类加载器加载的类不会被卸载,自定义类加载器才会被卸载
1.3 释放的内存很少
1.4 为什么早期没有一开始使用元空间的方式呢?早期是没有成熟的动态字节码技术的,现在cglib、asm技术、热更新技术可能会去创建新的类,会造成永久代的OOM,进而会引发堆区的OOM - 2.元空间是如何解决?
2.1 不放在堆区,放在直接内存 - 3.元空间内部是如何存储的?元空间存在的问题?以及后面会如何优化
类加载器加载的类在元空间的存储形式。存在的内存碎片化问题。比如说在内存中存在一块4字节单位的区域和一块3字节单位的区域,此时要分配6字节,但虽然内存空间有7字节,但是因为不是连续的,所以导致没法分配。JVM内部不会存在太多。但是自定义类加载器中这个问题会比较明显,如Tomcat可以自己去实现整理算法以调用JNI的形式
如果一直向下兼容,问题将会一直存在,无法得到解决,以后可能会出现最低版本的支持
为什么要用元空间区替代永久代呢?
- 1.内存碎片和垃圾回收问题
永久代是一个固定大小的内存区域,它存储了类的元数据、常量池等。随着时间的推移,永久代可能会发生内存碎片话,导致垃圾回收(GC)效率低下,甚至可能引发OutOfMemoryError错误。元空间使用的是本地内存,并且可以根据需要动态扩展和收缩,从而减少了内存碎片和GC问题 - 2.更灵活的内存管理
由于元空间使用的是本地内存,因此它不受JVM堆大小的限制。这意味着可以更灵活地管理内存使用,可以根据应用程序的需要分配更多的内存给元空间,而不会影响到java堆的大小 - 3.移除预定义的限制
由于元空间没有这样的预定义限制,它可以根据实际需求动态调整大小,这使得JVM更加健壮和可扩展。如果不指定的话,知道系统内存被使用完 - 4.简化的JVM架构
移除永久代简化了JVM的内存模型。现在,JVM的内存主要由堆(heap)、栈(stack)和本地内存中的元空间组成。这种简化有助于提高JVM的维护性和可理解性 - 5.更好的兼容性
随着Java应用程序和类库的不断发展,对元数据的需求也在不断增长,使用元空间可以更好地适应这种增长,因为它不受固定大小的限制 - 6.减少Full GC的影响
永久代的垃圾回收是Full GC的一部分,这通常会导致较长的停顿时间。由于元空间使用了不同的垃圾回收策略,可以减少Full GC的频率和影响
C++中Hotspot是如何将Klass对象放到方法区的?
C++有个技术叫做操作符重写,/vm/memory/allocation.hpp,操作符重写:new可以指定这个对象存在哪里
Java虚拟机栈
Java虚拟机栈(Java Virtual machine Stacks)是线程私有的,它的声明周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame(栈帧是方法运行时的基础数据结构))用于存储以下几个部分
- 1.局部变量表
- 2.操作数栈
- 3.动态连接
- 4.方法出口/返回地址
- 5.附加信息
经常有人把Java内存区分为堆内存(heap)和栈内存(stack),这种分发比较粗糙,java内存区域的划分实际上远比这复杂。这种划分方式的流行只能说明大多数程序员最关注的、与对象分配关系最密集的内存区域是这两块。
虚拟机栈和线程个数比为1:1
一个虚拟机栈中有多少栈帧?跟方法的调用次数成正比
局部变量表
局部变量表存放了编译器可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference类型,它不等同于对象本身,可能是一个指向对象的起始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象相关的位置)和returnAddress类型(指向了一条字节码指令的地址)。其中64位长度的long和double类型的数据会占用2个局部变量空间(Slot),其余的数据类型只占用1个。局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在栈帧中分配多大的局部变量空间时完全确定的,在方法运行期间不会改变局部变量表的大小。
在Java虚拟机规范中,对这个区域规定了两种异常状况:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果虚拟机栈可以动态扩展(当前大部分的Java虚拟机都可动态扩展,只不过Java虚拟机规范中也允许固定长度的虚拟机栈),如果扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常
局部变量表(Local Variable Table)是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量。在Java程序编译为Class文件时,就在方法的Code属性的max_locals数据项中确定了该方法所需要分配的局部变量表的最大容量。
局部变量表的容量以变量槽(Variable Slot,下称Slot)为最小单位,虚拟机规范中并没有明确指明一个Slot应占用的内存空间大小,只是很有导向性地说到每个Slot都应该能存放一个boolean、byte、char、short、int、float、reference或returnAddress累心地数据,这8种苏韩剧类型,都可以用32位或更小地物理内存来存放,但这种描述与明确指出"每个Slot占用32位长度地内存空间"是有一些差别地,它允许Slot的长度可以随着处理器、操作系统或虚拟机的不同而发生变化。只要保证即使在64位虚拟机中使用了64位的物理内存空间区实现一个Slot,虚拟机仍要使用对齐和补白的方式让Slot在外观上看起来与32位虚拟机中的一致。
既然前面提到了Java虚拟机的数据类型,在此再简单介绍一下他们。一个Slot可以存放一个32位以内的数据类型,Java中占用32位以内的数据类型有boolean、byte、char、short、int、float、reference(Java虚拟机规范中没有明确规定reference类型的长度,它的长度与实际使用32还是64位u虚拟机有关,如果是64位虚拟机,还与是否开启某些对象指针压缩的优化有关,这里暂且只取32位虚拟机的reference长度)和returnAddress8种类型。前面6中不需要多家解释,可以按照Java语言中对应数据类型的概念区理解它们(仅是这样理解而已,Java语言与Java虚拟机中的基本数据类型是存在本质差别的),而第7种reference类型表示对一个对象实例的引用,虚拟机规范既没有说明它的长度,也没有明确指出这种引用应有怎样的结构。但一般来说,虚拟机实现至少都应当能通过这个引用做到两点:
- 1.从此引用直接或间接地查找到对象在堆中的数据存放的起始地址索引
- 2.此引用中直接或间接地查找到对象所属数据类型在方法去中的存储的类型信息,否则无法实现Java语言规范中定义的语法约束
(并不是所有语言的对象引用都能满足这两点,例如C++语言,默认情况下(不开启RTTI支持的其概况),就之只能满足第一点,而不满足第二点。这也是为何C++中提供Java语言里很常见的反射的根本原因)
对于64位的数据类型,虚拟机会以高位对齐的方式为其分配两个连续的Slot空间,Java语言中明确的(reference类型则可能是32位也可能是64位)64位的数据类型只有long和double两种。值得一提的是,这里把long和double数据类型分割存储的做法与"long和double的非原子性协定"中把一次long和double数据类型读写分割位两次32位读写的做法有些类似。不过局部变量表建立在线程的堆栈上,是线程私有的数据,无论读写两个连续的Slot是否为原子操作,都不会引起数据安全问题。
虚拟机通过索引定位的方式使用局部变量表,索引值的范围是从0开始至局部变量表最大的Slot数量。如果访问的是32位数据类型的变量,索引n就代表了使用第n个Slot,如果是64位数据类型的变量,则说明会同时使用n和n+1两个Slot。对于两个相邻的共同存放一个64位数据的两个Slot,不允许采用任何方式单独访问其中的某一个,Java虚拟机规范中明确要求了如果遇到进行这种操作的字节码序列,虚拟机应该在类加载器的校验阶段抛出异常。
编译优化:方法内部代码块中的变量是不会写到字节码文件中的
为什么C++提供Java语言里反射的原因?
- 1.现代语言特性需求:随着变成语言的发展,现代变成语言普遍支持反射机制,因为它可以大大提高程序的灵活性和可扩展性。C++作为一门长期发炸你的语言,也在不断地更细你和增加新特性,以保持其竞争力
- 2.运行时类型信息(RTTI):C++中的反射机制是通过运行时类型信息实现的,这允许程序在运行时获取对象的类型信息,并进行相应的操作。这是实现多态、动态绑定等高级编程概念的基础
- 3.框架和库开发:反射机制杜宇框架和库的开发尤为重要,因为它可以使这些框架和库更加通用和强大。例如,它可以使序列化、反序列化、对象关系映射(ORM)等操作更加容易实现
- 4.增强互操作性:C++与其他支持反射的语言(如Java、C#等)进行交互时,反射机制可以提供更好的互操作性。例如C++/CLI是一种特殊的C++方言,用于与.NET框架交互,其中就包含了反射特性
- 5.动态编程:虽然C++是一门静态类型语言,但在某些情况下,开发者可能需要动态编程的能力,例如在脚本语言或插件系统中。反射可以提供这种能力
- 6.社区需求:长期以来,C++社区中一直有呼声要求增加反射机制。随着标准的更新,C++委员会逐渐考虑将这些需求纳入语言标准
- 7.代码生成和元编程:反射机制可以与模板元编程结合使用,以实现更高级的代码生成技术,这在一些复杂的系统中非常有用
需要注意的是,C++的反射机制与传统上Java中的反射并不完全相同。C++的反射能力相对较弱,通常是通过RTTI和模板元编程等技术部分实现的。而且直至2024,C++标准中并没有完整的反射机制,但有一些提案正在尝试将更完整的反射特性引入C++
操作数栈
操作数栈(Operand Stack)也常称为操作栈,他是一个后入先出(Last In First Out, LIFO)栈。同局部变量表一样,操作数栈的最大深度也在编译的时候写入到Code属性的max_stacks数据项中。操作数栈的每一个元素可以是任意的Java数据类型,包括long和double.32位数据类型所占的栈容量为1,64位数据类型所占的栈容量为。在方法执行的任何时候,操作数栈的深度都不会超过max_stacks数据项中设定的最大值。
当一个方法刚刚开始执行的时候,这个方法的操作数栈是空的,在方法的执行过程中,会有各种字节码指令往操作数栈中写入和提取内容,也就是出栈/入栈操作。例如,在做算术运算的时候是通过操作数栈来进行的,又或者在调用其他方法的时候是通过操作数栈来进行参数传递(A方法的返回值作为B方法的入参这种)。
举个例子,整数加法的字节码指令iadd在运行的时候操作数栈中最接近栈顶的两个元素已经存入了两个int类型的数值,当执行这个指令的时候,会将这两个int值出栈并相加,然后将相加的结果入栈。
操作数栈中元素的数据类型必须与字节码指令的序列严格匹配,在编译程序代码的时候,编译器要严格保证这一点,在类校验阶段的数据流分析中还要再次验证这一点。再以上面的iadd指令为例,这个指令用于整型数假发,它在执行时,最接近栈顶的两个元素的数据类型必须为int类型,不能出现一个long和一个float使用iadd命令相加的情况。
另外,在概念模型中,两个栈帧作为虚拟机栈的元素,是完全相互独立的。但在大多数虚拟机的实现里都会做一些优化处理,令两个栈帧出现一部分重叠。让下面栈帧的部分操作数栈与上面栈帧的部分局部变量表重叠在一起,这样在进行方法调用时就可以公用一部分数据,无需进行额外的参数复制传递,重叠的过程如图所示。Java虚拟机的解释执行引擎称为"基于栈的执行引擎",其中所指的"栈"就是操作数栈。
动态链接
每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接(Dynamic Linking)。我们知道Class文件的常量池中有大量的符号引用,字节码中的方法调用指令就以常量池中指向方法的符号引用作为参数。这些符号引用一部分会在类加载阶段或者第一次使用的时候就转化为直接引用,这种转化称为静态解析。另外一部分将在每一次运行期间转化为直接引用,这部分称为动态连接
方法返回地址
当一个方法开始执行后,只有两种方式可以退出这个方法。第一种方式是执行引擎遇到任意一个方法返回的字节码指令,这死后可能会有返回值传递给上层的方法调用者(调用当前方法的方法称为调用者),是否有返回值和返回值的类型将根据遇到何种方法返回指令来决定,这种退出方法的方式称为正常完成出口(Normal Method Invocation Completion)。另外一种退出方式是,在方法执行过程中遇到了异常,并且这个异常没有在方法体内得到处理,无论是Java虚拟机内部产生的异常,还是代码中使用athrow字节码指令产生的异常,只要在本方法的异常表中没有搜索到匹配的异常处理器,就会导致方法退出,这种退出方法的方式称为异常完成出口(Abrupt Method Invocation Completion)。一个方法使用异常完成出口的方式退出,是不会给它的上层调用者产生任何返回值的。
无论采用何种退出方式,在方法退出之后,都需要返回到方法被调用的位置,程序才能继续执行,方法返回时可能需要在栈帧中保存一些信息,用来帮助恢复它的上层方法的执行状态。一般来说,方法正常退出时,调用者的PC计数器的值可以作为返回地址,栈帧中很可能会保存这个计数器值。而方法异常退出时,返回地址是要通过异常处理器表来确定的,栈帧中一般不会保存这部分信息。
方法退出的过程实际上就等同于把当前栈帧出栈,因此退出时可以能执行的操作有:恢复上层方法的局部变量表和操作数栈,把返回值(如果有的话)压入调用者栈帧的操作数栈中,调整PC计数器的值以指向方法调用指令后面的一条指令等。
附加信息
虚拟机规范允许具体的虚拟机实现增加一些规范里没有描述的信息到栈帧之中,例如与调试相关的信息,这部分信息完全取决于具体的虚拟机实现,在实际开发中,一般会把动态链接、方法返回地址与其他附加信息全部归为一类称为栈帧信息
相关文章:

【JVM】JVM内存模型与操作系统内存模型(一)
JVM内存模型与操作系统内存模型 Java进程在操作系统内存中的结构 JVM内存模型 可以这样理解:JVM内存模型其实就是JVM在启动的时候从操作系统内存中要了一块大内存,然后将这个大内存分成五个区域:方法区、堆区、虚拟机栈、本地方法栈、本地方法栈、程序计数器.其实叫…...

构建基于LLM的应用程序——为您的应用程序选择合适的LLM
。 在本章中,将引导您完成为应用程序选择合适LLM的过程。我们将涵盖以下几个主题: 市场上最具前景的LLM概览比较LLM时应使用的主要标准和工具规模与性能之间的权衡 在本章结束时,您应该能够清楚地理解如何为您的应用程序选择合适的LLM&…...

raksmart站群服务器多IP配置要求
RakSmart是一家提供多种服务器解决方案的服务商,其中包括针对站群服务的多IP服务器。这类服务器特别适合那些需要大量独立IP地址的业务,例如站群、多域名托管等。下面我们就来了解一下RakSmart站群服务器的多IP配置要求及相关信息。 什么是站群服务器? …...

【Web IDE】WebContainer容器在浏览器中启动运行nodejs并使用vite启动项目
参考了文章WebContainer/api 基础(Web IDE 技术探索 一) 在浏览器中运行vite的vue3项目 示例站点 最终效果 主要流程 加载WebContainer》加载代码压缩包>解压代码压缩包》生成文件树》挂载文件树》pnpm安装依赖》启动项目 代码 <script setup…...

Linux 多线程
目录 1 多线程的概念 1.1 再次理解进程的地址空间和页表 1.2 线程 2 线程控制 2.1 创建线程 pthread_create 2.2终止线程 2.3 线程等待 2.4 线程取消 2.5 线程分离 3 原生线程库 4 互斥 (锁) pthread_mutex_t pthread_mutex_init pthread_mute…...
C语言编写三子棋游戏:从概念到思路到实现
目录 一.文章概述 二.游戏规则概述 三.理解思路 1. 定义游戏数据结构 2. 游戏搭建思路及其步骤 菜单选择列表: 初始化棋盘:所有位置均为空格 创建棋盘样式 设置玩家下棋 设置电脑下棋 检查游戏状态: 四.代码示例 一.game.c部分 …...
React.js如何使用Bootstrap
在 React.js 项目中使用 Bootstrap 有多种方法,主要包括直接引入 Bootstrap CSS 文件和使用 React Bootstrap 库。下面将详细介绍这两种方法。 方法一:直接引入 Bootstrap CSS 文件 这是最简单的方式,只需在项目中引入 Bootstrap 的 CSS 文…...

深入解析:Redis与Nacos分布式锁在业务中的具体应用
时间:2024年08月22日 作者:小蒋聊技术 邮箱:wei_wei10163.com 微信:wei_wei10 音频地址:https://xima.tv/1_HBPYxC?_sonic0 希望大家帮个忙!如果大家有工作机会,希望帮小蒋内推一下&#x…...

MySQL索引的性能优化
1.数据库服务器的优化步骤 在数据库调优中,我们的目标就是响应时间更快,吞吐量更大。利用宏观的监控工具和微观的日志分析可以帮我们快速找到调优的思路和方式 数据库服务器的优化步骤 当我们遇到数据库调优问题的时候,该如何思考呢…...
协方差详解及在日常生活中的应用实例——天气温度与冰淇淋销量的关系
协方差详解及在日常生活中的应用实例——天气温度与冰淇淋销量的关系 文章目录 协方差详解及在日常生活中的应用实例——天气温度与冰淇淋销量的关系引言协方差的概念与背景数学公式推导实例背景数据收集计算过程结果解释计算相关系数为什么使用协方差?结论商业启示…...

Spring Boot3.3.X整合Mybatis-Plus
前提说明: 项目的springboot版本为:<version>3.3.2</version> 需要整合的mybatis-plus版本:<version>3.5.7</version> 废话不多说,开始造吧 1.准备好数据库和表 2.配置全局文件application.properti…...

快速了解软件测试——测试用例的方法
测试用例的编写方法有八种,其中等价类、边界值、判定表、场景法、流程图重要且使用得多 ●等价类●边界值●判定表●因果图[了解]●正交法[了解]●场景法●流程图●错误推测法[了解] 1、等价类 为什么要用等价类划分法? ●从大量数据中划分范围(等价类),然后从每…...

多线程、多进程,还是异步?-- Python 并发 API 如何选择
如何选择正确的 Python 并发 API模块 ? Python 标准库提供了三种并发 API , 如何知道你的项目应该使用哪个 API? 在本教程将带逐步了解各API的特性、区别以及各自应用场景,指导你选择最合适的并发 API。 多线程、多进程࿰…...

汽车服务管理系统 _od8kr
TOC springboot580汽车服务管理系统 _od8kr--论文 系统概述 该系统由个人管理员和员工管理,用户三部分组成。其中:用户进入系统首页可以实现首页,热销汽车,汽车配件,汽车资讯,后台管理,在线客…...

带你玩转小程序推广,实现短链接一键跳转
不知道各位有没有想过,短链接直接跳转到微信小程序到底该怎么操作呢?掌握这个小技能,能让你的推广效率大幅提升哦。今天就给大家分享一个全新方法,教你如何从短链接直接跳转到微信小程序,实现高效的一键式跨越。 一、…...

OpenDDS的Rtps_Udp传输协议可靠性QoS收发基本流程
OpenDDS中,实现了Rtps_Udp传输协议(非纯udp)的可靠性传输。传输的线程包括: 1)发送方线程主要线程和定时器 《1》应用线程 《2》网络异步发送线程 《3》Heartbeat定时器 《4》Nak_response定时器 2)接收方主要线程和定时器 《1》网络异步接收线程 《2》heartbeat_respons…...
体育数据API纳米奥运会数据API:高阶数据包接口文档API示例⑦
纳米体育数据的数据接口通过JSON拉流方式获取200多个国家的体育赛事实时数据或历史数据的编程接口,无请求次数限制,可按需购买,接口稳定高效;覆盖项目包括足球、篮球、网球、电子竞技、奥运等专题、数据内容。 纳米数据API2.0版本…...

【中项第三版】系统集成项目管理工程师 | 第 15 章 组织保障
前言 本章的知识点预计上午会考1-2分,下午可能会考,一般与其他管理领域进行结合考查。学习要以教材为主。 目录 15.1 信息和文档管理 15.1.1 信息和文档 15.1.2 信息(文档)管理规则和方法 15.2 配置管理 15.2.1 基本概念 …...

数据结构——顺序栈和链式栈
目录 引言 栈的定义 栈的分类 栈的功能 栈的声明 1.顺序栈 2.链式栈 栈的功能实现 1.栈的初始化 (1)顺序栈 (2)链式栈 (3)复杂度分析 2.判断栈是否为空 (1)顺序栈 (2)链式栈 (3)复杂度分析 3.返回栈顶元素 (1)顺序栈 (2)链式栈 (3)复杂度分析 4.返回栈的大…...

PHP轻创推客集淘客地推任务平台于一体的综合营销平台系统源码
🚀轻创推客,营销新纪元 —— 集淘客与地推任务于一体的全能平台🌐 🌈【开篇:营销新潮流,轻创推客引领未来】 在瞬息万变的营销世界里,你还在为寻找高效、全面的营销渠道而烦恼吗?&…...

Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...

Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...

算法岗面试经验分享-大模型篇
文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer (1)资源 论文&a…...
在Ubuntu24上采用Wine打开SourceInsight
1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...

安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...

DingDing机器人群消息推送
文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人,点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置,详见说明文档 成功后,记录Webhook 2 API文档说明 点击设置说明 查看自…...
django blank 与 null的区别
1.blank blank控制表单验证时是否允许字段为空 2.null null控制数据库层面是否为空 但是,要注意以下几点: Django的表单验证与null无关:null参数控制的是数据库层面字段是否可以为NULL,而blank参数控制的是Django表单验证时字…...