CN116932085A - 一种启动WebAssembly程序的方法、计算机设备及存储介质 - Google Patents
一种启动WebAssembly程序的方法、计算机设备及存储介质 Download PDFInfo
- Publication number
- CN116932085A CN116932085A CN202310918129.XA CN202310918129A CN116932085A CN 116932085 A CN116932085 A CN 116932085A CN 202310918129 A CN202310918129 A CN 202310918129A CN 116932085 A CN116932085 A CN 116932085A
- Authority
- CN
- China
- Prior art keywords
- memory
- wasm
- file
- virtual memory
- virtual
- Prior art date
- Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
- Pending
Links
- 238000000034 method Methods 0.000 title claims abstract description 101
- 238000003860 storage Methods 0.000 title claims description 20
- 230000015654 memory Effects 0.000 claims abstract description 587
- 238000013507 mapping Methods 0.000 claims abstract description 120
- 238000005516 engineering process Methods 0.000 claims abstract description 23
- 230000006870 function Effects 0.000 description 88
- 230000008569 process Effects 0.000 description 51
- 230000007246 mechanism Effects 0.000 description 24
- 238000010586 diagram Methods 0.000 description 22
- 230000018109 developmental process Effects 0.000 description 13
- 238000011161 development Methods 0.000 description 11
- 230000003068 static effect Effects 0.000 description 10
- 229910052799 carbon Inorganic materials 0.000 description 9
- 230000006872 improvement Effects 0.000 description 9
- 238000005457 optimization Methods 0.000 description 9
- 238000004590 computer program Methods 0.000 description 8
- 230000001419 dependent effect Effects 0.000 description 7
- 238000012545 processing Methods 0.000 description 7
- 230000004048 modification Effects 0.000 description 5
- 238000012986 modification Methods 0.000 description 5
- 230000001960 triggered effect Effects 0.000 description 5
- 230000006399 behavior Effects 0.000 description 4
- 238000013519 translation Methods 0.000 description 4
- 238000004458 analytical method Methods 0.000 description 3
- 238000004891 communication Methods 0.000 description 3
- 230000008878 coupling Effects 0.000 description 3
- 238000010168 coupling process Methods 0.000 description 3
- 238000005859 coupling reaction Methods 0.000 description 3
- 238000013461 design Methods 0.000 description 3
- 230000000694 effects Effects 0.000 description 3
- 230000014616 translation Effects 0.000 description 3
- 239000008186 active pharmaceutical agent Substances 0.000 description 2
- 230000005540 biological transmission Effects 0.000 description 2
- 238000004364 calculation method Methods 0.000 description 2
- 230000003993 interaction Effects 0.000 description 2
- JEIPFZHSYJVQDO-UHFFFAOYSA-N iron(III) oxide Inorganic materials O=[Fe]O[Fe]=O JEIPFZHSYJVQDO-UHFFFAOYSA-N 0.000 description 2
- 238000004519 manufacturing process Methods 0.000 description 2
- 239000000463 material Substances 0.000 description 2
- 230000003287 optical effect Effects 0.000 description 2
- 230000008520 organization Effects 0.000 description 2
- OKTJSMMVPCPJKN-UHFFFAOYSA-N Carbon Chemical compound [C] OKTJSMMVPCPJKN-UHFFFAOYSA-N 0.000 description 1
- 108010001267 Protein Subunits Proteins 0.000 description 1
- 230000004075 alteration Effects 0.000 description 1
- 238000013459 approach Methods 0.000 description 1
- 238000003491 array Methods 0.000 description 1
- 230000008901 benefit Effects 0.000 description 1
- 230000003139 buffering effect Effects 0.000 description 1
- 230000001413 cellular effect Effects 0.000 description 1
- 230000008859 change Effects 0.000 description 1
- 239000007795 chemical reaction product Substances 0.000 description 1
- 238000010276 construction Methods 0.000 description 1
- 230000007423 decrease Effects 0.000 description 1
- 230000007547 defect Effects 0.000 description 1
- 229910021389 graphene Inorganic materials 0.000 description 1
- 238000012423 maintenance Methods 0.000 description 1
- 230000005055 memory storage Effects 0.000 description 1
- 230000005012 migration Effects 0.000 description 1
- 238000013508 migration Methods 0.000 description 1
- 238000003032 molecular docking Methods 0.000 description 1
- 229920001296 polysiloxane Polymers 0.000 description 1
- 238000011112 process operation Methods 0.000 description 1
- 239000000047 product Substances 0.000 description 1
- 230000000750 progressive effect Effects 0.000 description 1
- 230000003252 repetitive effect Effects 0.000 description 1
- 230000004044 response Effects 0.000 description 1
- 239000010979 ruby Substances 0.000 description 1
- 229910001750 ruby Inorganic materials 0.000 description 1
- 230000033772 system development Effects 0.000 description 1
- 239000011800 void material Substances 0.000 description 1
Classifications
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F9/00—Arrangements for program control, e.g. control units
- G06F9/06—Arrangements for program control, e.g. control units using stored programs, i.e. using an internal store of processing equipment to receive or retain programs
- G06F9/44—Arrangements for executing specific programs
- G06F9/445—Program loading or initiating
- G06F9/44505—Configuring for program initiating, e.g. using registry, configuration files
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F9/00—Arrangements for program control, e.g. control units
- G06F9/06—Arrangements for program control, e.g. control units using stored programs, i.e. using an internal store of processing equipment to receive or retain programs
- G06F9/44—Arrangements for executing specific programs
- G06F9/455—Emulation; Interpretation; Software simulation, e.g. virtualisation or emulation of application or operating system execution engines
- G06F9/45533—Hypervisors; Virtual machine monitors
- G06F9/45558—Hypervisor-specific management and integration aspects
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F9/00—Arrangements for program control, e.g. control units
- G06F9/06—Arrangements for program control, e.g. control units using stored programs, i.e. using an internal store of processing equipment to receive or retain programs
- G06F9/44—Arrangements for executing specific programs
- G06F9/455—Emulation; Interpretation; Software simulation, e.g. virtualisation or emulation of application or operating system execution engines
- G06F9/45533—Hypervisors; Virtual machine monitors
- G06F9/45558—Hypervisor-specific management and integration aspects
- G06F2009/45583—Memory management, e.g. access or allocation
Landscapes
- Engineering & Computer Science (AREA)
- Software Systems (AREA)
- Theoretical Computer Science (AREA)
- Physics & Mathematics (AREA)
- General Engineering & Computer Science (AREA)
- General Physics & Mathematics (AREA)
- Devices For Executing Special Programs (AREA)
Abstract
一种启动WebAssembly程序的方法,包括:加载wasm字节码并解析,得到wasm模块对象;根据解析得到的wasm模块对象创建线性内存并填充线性内存;创建内存文件,并将所述线性内存中的数据写入到该内存文件中;启动每个wasm实例后:采用内存映射技术基于所述内存文件创建一段虚拟内存映射区;通过读/写创建的虚拟内存映射区来对所述内存文件进行读/写操作。
Description
技术领域
本说明书实施例属于编译技术领域,尤其涉及一种启动WebAssembly程序的方法、计算机设备及存储介质。
背景技术
WebAssembly是由W3C社区组开发的开放标准,是一种安全,可移植的低级代码格式,专为高效执行和紧凑表示而设计,可以接近原生的性能运行,并为诸如C、C++、Java、Go等语言提供一个编译目标。WASM虚拟机起初设计的目的是用于解决Web程序日益严峻的性能问题,由于其具有的优越特性,被越来越多的非Web项目所采用,例如替代区块链智能合约执行引擎EVM。
发明内容
本发明的目的在于提供一种启动WebAssembly程序的方法、计算机设备及存储介质,包括:
一种启动WebAssembly程序的方法,包括:
加载wasm字节码并解析,得到wasm模块对象;根据解析得到的wasm模块对象创建线性内存并填充线性内存;创建内存文件,并将所述线性内存中的数据写入到该内存文件中;采用内存映射技术基于所述内存文件创建预设数量的虚拟内存映射区;
启动每个wasm实例后:
选择未占用的虚拟内存映射区并标记为已占用,通过读/写选择的虚拟内存映射区来对所述内存文件进行读/写操作。
一种计算机设备,包括:
处理器;
以及存储器,其中存储有程序,其中在所述处理器执行所述程序时,进行以下操作:
加载wasm字节码并解析,得到wasm模块对象;根据解析得到的wasm模块对象创建线性内存并填充线性内存;创建内存文件,并将所述线性内存中的数据写入到该内存文件中;采用内存映射技术基于所述内存文件创建预设数量的虚拟内存映射区;
启动每个wasm实例后:
选择未占用的虚拟内存映射区并标记为已占用,通过读/写选择的虚拟内存映射区来对所述内存文件进行读/写操作。
一种存储介质,用于存储程序,其中所述程序在被执行时进行以下操作:
加载wasm字节码并解析,得到wasm模块对象;根据解析得到的wasm模块对象创建线性内存并填充线性内存;创建内存文件,并将所述线性内存中的数据写入到该内存文件中;采用内存映射技术基于所述内存文件创建预设数量的虚拟内存映射区;
启动每个wasm实例后:
选择未占用的虚拟内存映射区并标记为已占用,通过读/写选择的虚拟内存映射区来对所述内存文件进行读/写操作。
附图说明
为了更清楚地说明本说明书实施例的技术方案,下面将对实施例描述中所需要使用的附图作简单地介绍,显而易见地,下面描述中的附图仅仅是本说明书中记载的一些实施例,对于本领域普通技术人员来讲,在不付出创造性劳动性的前提下,还可以根据这些附图获得其他的附图。
图1是一实施例中Java程序的编译、执行过程的示意图;
图2是一编译器可以在将Java源代码编译成wasm文件的过程的流程图;
图3是一实施例中字节码结构和虚拟机模块示意图;
图4是一实施例中的方法流程图;
图5是一实施例中wasm文件与线性内存、受管内存中的示意图;
图6是一实施例中用户态、内核态的示意图;
图7是一实施例中用户态、内核态的示意图;
图8是一实施例中用户态、内核态的示意图;
图9是一实施例中用户态、内核态的示意图;
图10是一实施例中解释执行和JIT执行的示意图;
图11是一实施例中的方法流程图;
图12是一实施例中用户态、内核态的示意图;
图13是一实施例中用户态、内核态的示意图;
图14是一实施例中用户态、内核态的示意图;
图15是一实施例中用户态、内核态的示意图;
图16是一实施例中用户态、内核态的示意图;
图17是一实施例中用户态、内核态的示意图。
具体实施方式
为了使本技术领域的人员更好地理解本说明书中的技术方案,下面将结合本说明书实施例中的附图,对本说明书实施例中的技术方案进行清楚、完整地描述,显然,所描述的实施例仅仅是本说明书一部分实施例,而不是全部的实施例。基于本说明书中的实施例,本领域普通技术人员在没有作出创造性劳动前提下所获得的所有其他实施例,都应当属于本说明书保护的范围。
高级计算机语言便于人们编写,阅读交流,维护,机器语言则是计算机能直接解读、运行的。编译器可以将汇编或高级计算机语言源程序(Source program)作为输入,翻译成目标语言(Target language)机器代码的等价程序。源代码一般为高级语言(High-levellanguage),如C、C++等,而目标则是机器语言的目标代码(Object code),有时也称作机器代码(Machine code)。进而,可以由CPU执行这样的机器码(或者称为“微处理器指令”)。这种方式一般称为“编译执行”。
编译执行一般不具有跨平台的可扩展性。由于存在不同厂商、不同品牌和不同代的CPU,而这些不同的CPU支持的指令集很多情况下是不同的,如x86指令集,ARM指令集等,且同一厂商同一品牌但不同代的CPU支持的指令集也不完全相同,因此,用同样的高级语言编写的同样的程序代码,在不同CPU上被编译器转换出来的机器码可能不同。具体的,编译器在转换高级语言编写的程序代码到机器码的过程中,会结合具体的CPU指令集的特点(如向量指令集等)进行优化以提升程序执行的速度,而此类优化往往与具体的CPU硬件相关。这样,同样的机器码,一个在x86平台上可以运行,但另一个在ARM上就可能无法运行;甚至同样是x86平台,随着时间的推移,指令集也不断丰富和扩展,这就导致不同代的x86平台运行的机器码也有不同。而且,由于执行机器码需要由操作系统内核对CPU进行调度,因此即使是同样的硬件,在不同操作系统下支持运行的机器码也可能不同。
C语言和C++语言即与平台有一定的关联性。这主要是因为它们在设计时就是为了尽可能地提供对底层硬件的直接访问,以实现高效的执行性能。这种设计使得C和C++能够用于系统级编程,如操作系统和嵌入式系统开发,这也是它们的主要应用领域。由于C/C++语言提供了对底层硬件的直接访问,所以它们在编译时需要考虑目标平台的具体细节,包括处理器架构、操作系统接口、系统调用等。因此,C和C++代码通常为特定平台编译,生成的二进制执行文件只能在该平台上运行。不过,也需要指出的是,虽然C/C++语言本身与平台有关,但是可以通过一些方式实现跨平台编程。例如,编写符合ANSI C或ISOC标准的代码、使用跨平台的库和框架等。此外,也有一些工具可以帮助开发者在不同平台上构建和运行C/C++代码,例如GCC和CMake。相比之下,Java语言设计时的主要目标之一就是支持“一次编写,到处运行”。Java代码会被编译为字节码,然后运行在Java虚拟机(JVM)上,由JVM负责将字节码转换为特定平台的机器码。因此,只要有适合的JVM,Java程序就可以在任何平台上运行,无需考虑平台的具体细节。这就是Java的与平台无关性。
相应的,不同于C、C++编译执行,还存在一种“解释执行”的程序运行方式。例如对于Java、C#等高级语言而言,此时编译器完成的功能是把源码(SourceCode)编译成通用中间语言的字节码(ByteCode)。
比如Java语言,将Java源代码通过Java的编译器编译成标准的字节码,这里编译器不针对任何实际的硬件处理器的指令集,而是定义了一套抽象的标准指令集。编译成的标准字节码一般无法在硬件CPU上直接运行,因此引入了一个虚拟机,即JVM,JVM运行在特定的硬件处理器上,用以解释和执行编译后的标准字节码。
JVM是Java Virtual Machine(Java虚拟机)的缩写,是一种虚构出来的计算机,往往通过在实际的计算机上仿真模拟各种计算机功能来实现。JVM屏蔽了与具体的硬件平台、操作系统等相关的信息,使Java程序只需要是生成的可在Java虚拟机上运行的标准字节码,就可以在多种平台上不加修改地运行。
Java语言的一个非常重要的特点就是与平台的无关性。而使用Java虚拟机是实现这一特点的关键。一般的高级语言如果要在不同的平台上运行,至少需要编译成不同的目标代码。而引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。这就是Java的能够“一次编译,到处运行”的原因。这样,只要保证JVM能够正确执行.class文件,就可以运行在诸如Linux、Windows、MacOS等不同的操作系统平台上了。
JVM运行在特定的硬件处理器上,负责针对所运行的特定处理器而进行字节码的解释和执行,并向上屏蔽这些底层的差异,呈现给开发者以标准的开发规范。JVM在执行字节码时,实际上最终还是把字节码解释成具体平台上的机器指令执行。具体的,JVM接收到输入的字节码后,逐句解释其中的每一条指令,并翻译成适合当前机器的机器码来运行,这些过程例如由称为Interpreter的解释器进行解释和执行。这样一来,编写Java程序的开发者不需要考虑编写后的程序代码将运行在哪种硬件平台上。JVM本身的开发是由Java组织的专业开发人员完成,以将JVM适配到不同的处理器架构上。迄今为止,主流的处理器架构只有有限的几种,如X86,ARM,RISC-V,MIPS。专业的开发人员将JVM分别移植到支持这几种特定硬件的平台后,Java程序理论上就可以在所有的机器上运行了。JVM的移植工作通常由Java开发组织专业的人员提供的,这就极大减轻了Java应用开发者的负担。
上述Java程序的编译、执行的简要过程如图1所示。开发者开发的Java源代码一般是以.java作为扩展名。源文件经过编译器编译,生成.class扩展名的文件,这些.class文件即为字节码(bytecode)。字节码中包括字节码指令,也称为opcode,此外还包括操作数。JVM就是靠解析这些opcode和操作数来完成程序的执行的。当使用Java命令运行.class文件的时候,实际上是由Java虚拟机(JVM)加载和执行.class文件中的字节码。Java虚拟机是Java程序运行的核心部分,负责解释和执行Java字节码。JVM加载和执行.class文件中的字节码,实际上相当于在操作系统中启动了一个JVM进程,并向操作系统申请了一部分内存。这部分内存一般由JVM直接进行管理,具体又可以包括方法区、堆区、栈区等。JVM会按照字节码的指令逐行解释执行Java程序。在执行过程中,JVM会根据需要进行垃圾回收、内存分配和释放等操作,以保证Java程序的正常运行。JVM通过翻译加载的字节码来执行,具体包括两种执行方式。一种是常见的解释执行,即将opcode+操作数翻译成机器代码后交给操作系统运行,另外一种执行方式就是JIT(Just In Time),也就是即时编译,这种方式会在一定条件下将字节码编译成机器码之后再执行。
解释执行带来了跨平台可移植性,但由于bytecode的执行经历了JVM中间翻译的过程,因此执行效率不如上述编译执行效率高,这种效率的差异有时甚至可达几十倍。
如前所述,Java程序运行时需要将Java源代码编译成Java字节码(bytecode),即.class文件,然后由JVM加载和解释执行。因此,.class文件的大小对Java程序的性能有一定的影响。较小的.class文件通常意味着更快的加载速度和更少的内存占用。当Java虚拟机加载一个.class文件时,需要将其解析成内部的数据结构,然后将其存储在内存中。较小的.class文件可以更快地被解析和加载,从而减少加载时间和内存占用。此外,较小的.class文件可以更快地被传输和存储,从而有助于提高Java程序的整体性能。在网络传输或磁盘存储.class文件时,较小的文件需要更少的带宽和存储空间,可以更快地下载或读取,从而加快程序的启动速度和响应速度。
为了降低.class文件的大小,以及提供标准化的API,JVM中集成了大量的标准库,可以供Java程序依赖并使用。例如,开发者开发的Java源代码中包括Person.java和Main.java两个文件,且Main.java文件的头部声明导入Person。实际上,Main及其依赖的Person文件,在运行时还会涉及更多依赖的类,例如默认的父类和祖先类等(具体的一个例子例如是间接依赖的字符串类String.class)。如果JVM没有集成大量的依赖库,则在编译过程中需要对person、main及依赖的类一并进行编译,而这样得到的编译后的.class文件较多,整体体积也较大。JVM中集成大量的标准库之后,JVM在执行Java程序的过程中需要通过类加载器从外部加载的.class文件较少,且体积也较小,但是,仍然需要从内部加载依赖的类,例如是通过本地文件或网络加载。另一方面是JVM的动态加载特性。如前所述,JVM在执行java字节码的.class文件时,例如上述例子中的Person.class和Main.class,除了加载这两个字节码文件外,还需要加载很多依赖的类文件。动态加载特性,是JVM并不将所有的class一次性全部加载到内存中,而是按需加载class。具体的,JVM在使用到尚未被加载的class时,才去加载这个class。JVM的动态加载class特性,使得java程序在运行时可以根据条件来控制加载不同的实现类,从而降低内存的占用。内存的占用量直接影响JVM的执行效率。
Java等语言是使用运行在x86一类的通用硬件指令集的虚拟机,再执行自己的“汇编语言”(例如Java Bytecode)。实际上,Web平台在浏览器上也是采用类似于Java、Python的虚拟机环境,浏览器提供虚拟机环境执行一些JavaScript或者其他脚本语言,从而实现HTML页面的交互行为和一些网页的特定行为等,网页的特定行为例如是嵌入动态文本之类。随着业务需求越来越复杂,前端的开发逻辑也变得越来越复杂,相应的代码量随之变的越来越多,项目的开发周期也越来越长。除了逻辑复杂、代码量大,还有另一个原因是JavaScript这门语言本身的缺陷——JavaScript没有静态变量类型,从而会降低效率。具体的,JavaScript引擎会对JavaScript代码中执行次数较多的函数进行缓存和优化,例如JavaScript引擎将这样的代码编译成机器码后打包并发送到JIT Compiler,由JITCompiler编译为机器码;下次再执行到这个函数时,就会直接执行编译好的机器码。但是由于JavaScript采用的是动态变量,这个变量上一次可能是数组(Array),下一次就可能变成对象(Object)。这样,上一次JIT Compiler所做的优化就失去了作用,下一次又要重新进行优化。
在2015年,出现了WebAssembly(也简写为wasm)。WebAssembly是由W3C社区组开发的开放标准,是一种安全,可移植的低级代码格式,专为高效执行和紧凑表示而设计,可以接近原生的性能运行。WebAssembly是经过编译器编译之后的代码,体积小、起步快,在语法上完全脱离JavaScript,同时具有沙盒化的执行环境。WebAssembly使用静态类型,从而提升了执行效率。此外,WebAssembly将很多编程语言带到了Web中。而且,WebAssembly还进一步简化了一些执行过程,从而也带来执行效率的大幅提升。
WebAssembly是一个可移植、体积小、加载快并且兼容Web的全新格式,可以作为C/C++/Rust/Java等的编译目标。WebAssembly可以看做是Web平台的x86硬件通用指令集,作为一层中间语言,上层对接Java、Python、Rust、C++等,让这些语言都能编译成统一的格式,用于Web平台运行。
例如采用C++语言开发的源文件,一般以.cpp作为扩展名。cpp文件经过编译器编译,可以生成wasm格式的字节码。类似的,采用Java语言开发的源文件,一般以.java作为扩展名。java文件经过编译器编译,可以生成wasm格式的字节码。wasm格式的字节码可以封装在wasc文件中。wasc是合并字节码和ABI(Application Binary Interface,应用程序二进制接口)的文件。根据W3C社区开放标准实现的WebAssembly虚拟机(也称为wasm虚拟机或wasm运行环境,是执行WASM字节码的虚拟机运行环境),采用运行时加载wasm字节码并解释执行的方式实现。
比如要开发一款应用,如果想实现跨平台,例如采用java完成在Linux平台上的开发,用Objective-C实现iOS上的开发,用C#实现在Windows平台的开发...。如果有了wasm,只需要选择任意一门语言,然后编译成wasm文件,就可以分发到各个平台上。例如图2中所示,采用Java开发,经过编译器编译后可以得到wasm字节码,这个wasm字节码可以在集成有wasm虚拟机的各种平台上运行。
WASM虚拟机起初设计的目的是用于解决Web程序日益严峻的性能问题,由于其具有的优越特性,被越来越多的非Web项目所采用,例如替代区块链中的智能合约执行引擎EVM。
编译一般包括单文件编译和多文件联合编译两种。
在单文件编译中,所有的程序代码都包含在一个源文件中,可以使用任何一种编程语言来编写。在编译时,编译器会将这个源文件编译成一个目标文件(object file),目标文件例如可以是机器代码和一些元数据的二进制文件,也可以是如.class、.o之类。之后链接器将这个目标文件与其他文件(如依赖的静态库或动态库之类的文件)进行链接,生成最终的可执行程序或库文件。这里链接器的主要工作是将目标文件中未定义的符号(如函数、变量)与其他文件中的定义进行匹配和链接。
多文件联合编译,是将一个程序或库分为多个文件进行编写,并将这些文件编译成一个可执行文件或库文件。分开的多个文件中,一般来说每个源文件用于实现一个功能或一组相关功能。使用编译器将每个源文件编译成目标文件之后,类似的,采用连接器将多个目标文件链接成一个可执行文件或库文件。链接器的主要工作也是将目标文件中未定义的符号(如函数、变量)与其他目标文件或库文件中的定义进行匹配和链接。相比较而言,多文件联合编译具有更好的可维护性和可扩展性。使用多个文件来编写程序,可以更加清晰地组织代码,将不同的功能封装在不同的文件中,易于修改和维护。同时,多文件联合编译可以有效避免代码重复和依赖性问题,并且可以提高编译效率和可重用性。
在很多高级语言的程序开发过程中,例如开发C++程序,可以使用多个源文件来编写代码,并将它们编译为多个目标文件,最后链接成一个可执行文件或库文件。在这个过程中,只有一个源文件/目标文件中会包含main()函数,该main()函数作为程序的入口点。其他目标文件则包含各种定义、声明和实现,供main()函数使用。这种方式使得程序可以方便地进行模块化编程,并且可以避免代码重复和依赖性问题。Java程序也是类似的,一个Java程序只有一个入口点,但是可以包含多个类和多个包。当程序启动时,JVM会自动执行包含入口点的类中的main()函数(Java中程序的入口函数具体是public static voidmain(String[]args),这是Java程序的启动点),其他类中的方法可以被Main类中的main()函数调用,从而实现各种功能。
如前所述,Java程序可以被编译为wasm字节码,这个wasm字节码可以在集成有wasm虚拟机的各种平台上运行。Java程序被编译成WebAssembly字节码时,编译器可以自动生成start函数并置于所述WebAssembly字节码中。该start函数可以作为WebAssembly模块的入口点,可以用于执行Java虚拟机的初始化和为Java程序准备运行环境(例如加载必要的类库)等。并且,编译器会将Java程序的main函数插入到编译后得到的WebAssembly字节码的start函数中,以通过调用start函数来启动Java程序的main函数,从而启动整个Java程序的执行。上述wasm字节码中的start函数执行Java虚拟机的初始化和为Java程序准备运行环境,例如包括对java中堆(Heap)的初始化,以及各Java类的静态构造函数的调用、垃圾回收的初始化等。其它高级语言也是类似,也是可以通过WebAssembly编译器编译成WebAssembly模块,且编译得到的WebAssembly模块中包括一个start函数。
一个例子中,采用某种高级语言编写的源码(如go、TypeScript、Python等语言)可以是如下或类似的代码:
如上面源码所示,第1行声明并定义了这种高级语言中的全局变量sum,赋值为0。第3-6行为main函数,包括执行print函数和返回sum的值。第8行为将sum赋值为1。且第8行是全局作用域的操作。
上面源码经过编译后生成的wasm字节码(伪代码)如下:
如上wasm代码所示,第2行是将索引位置为0的变量赋值为0(双引号中用\0表示,对应源码中的sum,因为sum在源码中在最靠前的位置,所以索引为0);第3-5行是main函数,包括执行print函数和返回索引位置为0的变量(即源码中的sum)的值。第7-10行的start函数,其中包含对应上面第8行全局作用域的操作,因为这类全局作用域的操作适于在start函数中首先执行。第9行表示start函数标记为该wasm字节码的启动函数,即入口函数。第3行是其它函数代码,一般可以是源码中main()/apply()函数对应的wasm字节码。入口函数start执行完毕后,会继续执行第3行开始的代码。
可见,尽管在源码中没有start函数,而在编译成wasm模块的过程中,可以自动生成start函数。start函数的功能包括执行Java虚拟机的初始化和为Java程序准备运行环境。由于wasm的规范规定start函数在模块加载后会自动执行,因此Java程序主入口的调用通常也会放在start函数中,这样start函数的角色相当于程序的入口点,从而可以在模块实例化后自动执行,而不需要显式的调用。
wasm字节码在执行时,由WebAssembly虚拟机加载并运行该wasm字节码。图3所示为一个wasm字节码的内容及加载过程,其中各个段(segment或section)的内容具体如下:
表1、wasm模块中包括的各个段及内容说明
其中,内存段(Memory Section)5可以描述一个wasm模块内所使用的线性内存段的基本情况,比如这段内存的初始大小、以及最大可用大小等等。数据段(Data Section)11描述填充到线性内存中的一些元信息,存放各类模块可能使用到的数据,比如一段字符串、一些数字值等等。上面wasm代码示例中的data 0(对应源码中的sum=0)即是Data Section的一部分内容。此外,Data Section中还可以包括一些源码中诸如用到的标准库中像malloc函数等内存分配的底层实现和一些构造函数的调用、垃圾回收等的初始化内容。
总体来说,WebAssembly线性内存主要存储两类内容:
堆(heap):用于存储各种数据结构,如对象、数组等。
栈(stack):用于存储局部变量和函数调用时的其他临时信息。
WebAssembly的线性内存是一种连续的内存空间,用于存储程序运行时的数据。WebAssembly的线性内存是由多个页(Page)组成的,每个页的大小是64KB。线性内存的大小是以页为单位进行分配和管理的。在启动WebAssembly模块时,需要指定线性内存的初始大小和最大大小。如果程序需要更多的内存空间,可以通过将线性内存扩展到更大的页面数来动态分配更多的内存。线性内存中的每个字节都可以被wasm虚拟机直接访问。WebAssembly提供了多种类型的指令来支持对线性内存的读写操作,例如i32.load、i32.store、i64.load、i64.store等。这些指令可以读取或写入指定地址的内存数据,也可以进行偏移和对齐等操作。线性内存是WebAssembly的核心机制之一,它提供了高效、可靠的内存管理方式,可以使WebAssembly模块运行更加高效和稳定。
WebAssembly虚拟机中加载wasm字节码后,可以分配一个线性内存(LinearMemory)作为WebAssembly字节码使用的内存空间。具体的,可以根据上面所述的wasm文件中的内存段5来分配一个线性内存,并将数据段11中的内容填充到线性内存中。此外,对于wasm文件中的其它很多内容,在加载时可以被存储在由宿主环境(如浏览器或其它应用程序)管理的内存区域中,而非WebAssembly的线性内存。具体的存储位置取决于宿主环境的实现细节,并且对于WebAssembly代码来说,这部分内存区域通常是不可直接访问的。这类区域一般称为受管内存(Managed Memory)。上述wasm文件中的代码段(Code Section)10中存放着每个函数的具体定义,也就是函数体对应的一簇wasm指令集合。start函数的wasm指令集合即可以存放于该代码段10中。此外,源码中main()/apply()的部分也可以存放于该代码段10中。
结合上面的例子,wasm字节码中第2行(data 0“\0”),属于数据段;第3行和第7行以func开始的括号内的部分,属于代码段。
上面内容的一个具体例子可以如图3所示。并且,wasm模块每次加载到虚拟机并执行时,都将重复执行start函数中的内容,之后再执行其余的代码。具体的,WebAssembly虚拟机中加载wasm字节码后,可以根据受管内存中内存段5的内容分配一个线性内存作为WebAssembly字节码使用的内存空间,并将数据段11中的内容填充到该线性内存中。如上面的wasm代码例子中,第2行的索引位置为0的位置赋值为0即位于数据段11中。进而,WebAssembly虚拟机执行受管内存中代码段10中的代码,这里主要是第3行和第7行func开始的括号内的部分,这个示例中包括main和start两个函数。其中,如前所述start函数相当于代码的入口,因此首先执行start函数中的内容,之后再执行其它的代码(这里即main函数的代码)。执行该start函数的过程中,可能会对线性内存中的数据进行修改。例如上面wasm字节码中第8行(对应源码中第8的”sum=1;”)即是将数据段中同一索引位置0的变量修改为1。
前述提到,wasm字节码由WebAssembly虚拟机加载并运行。加载和执行是细分的两个过程。wasm字节码加载到虚拟机,包括解码wasm字节码并将解码结果拷贝到受管内存中。一次加载后可以对应有多次执行,即启动多个实例。启动每个实例后,都可以创建该实例对应的线性内存,并将受管内存中数据段内容填充到线性内存中,以及找到入口start函数并首先执行start函数、进而执行main()函数等的过程。启动一个实例后,将受管内存中数据段内容填充到线性内存的过程,也将带来一定开销。一些情况下,加载的wasm字节码中数据段的内容较大,而单次执行时这些较大的数据段中的内容并不会被用到很多,可能只用到较少的一部分。另一些情况下,单次执行的时长较短。上述这些情况,在每次执行时,都从受管内存中拷贝数据段内容填充到线性内存,时间方面的开销就相对明显。
以下结合图4介绍一个实施例中如何提供优化后的wasm字节码。
S410:加载wasm字节码并解析,得到wasm模块对象。
可以采用wasm虚拟机加载待优化的wasm字节码,具体可以是wasm虚拟机中的解释器。所述wasm字节码,具体可以是wasm字节码的二进制数据,可以是由WebAssembly编译器对高级语言的源代码编译后得到。进一步,可以采用wasm虚拟机中的解释器对加载的wasm字节码进行解析,解析主要包括解码的过程。wasm字节码文件一般是经过编码的二进制文件。通过解码,进而可以根据wasm标准得到该wasm模块中的各个Section ID(即上面表1中的ID),进而进行解析,即得到各个ID对应的Section中的细节内容。这样,通过解析所述wasm字节码,可以得到wasm模块对象,可以包括内存段、数据段和代码段中的start函数代码(这里仅列出了与该实施例关联较强的,实际上整体如前述表1,不再赘述)。
在一个具体实现中,如上面采用斐波那契函数的代码例子,解析得到的wasm模块对象如前述表1所示。
加载wasm字节码的结果,是wasm虚拟机的受管内存中保存解码后的wasm字节码二进制文件,如图5中所示。
S420:根据解析得到的wasm模块对象创建线性内存并填充线性内存。
S410中加载后wasm字节码后,可以创建线性内存。具体的,如前所述,加载过程中解析得到的wasm模块对象中的内存段5可以描述一个wasm模块内所使用的线性内存段的基本情况,比如这段内存的初始大小、以及最大可用大小等等。可以根据该内存段5创建所述线性内存。
进而,可以将解析得到的wasm模块对象中的数据段填充到创建的线性内存。可以结合图3和图5来理解这个过程。受管内存中的数据段11,来自于wasm文件中的数据段11。当然,受管内存中的内容整体上可以是一个wasm字节码中二进制文件的一份拷贝。
基于受管内存中的内存段在wasm虚拟机中创建一段线性内存后,可以将受管内存中的数据段11的内容填充至该线性内存中。线性内存中可以包括常量和变量,这取决于实际代码中的定义。
具体的,wasm模块对象中的数据段中通过偏移量的方式指定了数据地址及其值。数据地址可以通过编译器在编译环节中指定,具体取决于编译器的实现。例如,数据地址的偏移量1000对应的int类型的值,是4个字节的0x1234bc78。这样,偏移量1000~1003的地址存储了0x1234bc78。再例如,偏移量1006对应的int类型的值是0x9876de54,表示偏移量1006~1009的地址存储了0x1234bc78。而其中1004、1005这两个地址,可能并没有记录任何的值。这样,将wasm模块对象中的数据段填充到线性内存的过程,可以包括先将线性内存的所有值设置为0,然后将受管内存中的数据段11的内容填充至该线性内存中,后者具体可以是将数据段11中包含的偏移量及对应值填入线性内存中的对应位置,而线性内存中未被填入值的位置由于前者的初始化操作已设置为0。结合本段中的例子,也就是说,1004、1005这两个偏移量对应的线性内存中的位置的值为0。
S430:创建内存文件,并将所述线性内存中的数据写入到该内存文件中。
以Linux中的内存文件举例说明,其它操作系统也有类似的机制。
Linux系统中,内存文件(Memory-based file)是一种特殊的文件类型,其并不直接存储在硬盘上,而是存储在内存中。这使得对这些文件的读写操作变得非常快,因为可以避免磁盘I/O的开销。
内存文件在Linux系统中的实现,主要是通过tmpfs或ramfs文件系统。它们都可以创建一个在内存中的文件系统,用户和应用程序可以像使用普通的文件系统一样对其进行操作。具体来说,tmpfs是一种基于内存和swap区的文件系统,它会根据文件系统的使用情况和系统的内存情况动态地调整大小。当内存紧张时,tmpfs会将一部分数据写入swap区,从而释放内存。而ramfs与tmpfs类似,ramfs也是一种内存文件系统,但是它只使用内存,不使用swap区。这意味着当ramfs使用的内存增多时,系统的可用内存就会减少。并且,ramfs没有大小限制,可以一直使用直到耗尽所有物理内存。
总体来说,内存文件在Linux系统中被广泛用于需要高速读写的场景,例如:系统临时文件、缓存文件等。但是,因为内存文件在系统重启后内容会临时丢失,所以不适合存储需要持久化的数据。
内存文件的主要特点包括:
·内存文件不占用磁盘空间,存在于内存。
·可以使用标准的文件操作API访问,如open、read、write等。
·多个进程可以同时映射同一个内存文件,实现共享内存。
·内存文件可以被映射到进程虚拟地址空间,通过内存访问提高效率。
·可以给内存文件设置大小,OPS系统会自动分配物理内存页。
·关闭最后一个对内存文件的引用后,内存文件会被自动释放。
·常用来作为高速缓存,共享内存,共享对象等。
创建内存文件后,可以将所述线性内存中的数据写入到该内存文件中。具体的,可以将S420中填充后的线性内存中的数据写入到该内存文件中,不再赘述。
S440:采用内存映射技术基于所述内存文件创建虚拟内存映射区。
如前所述,wasm字节码由WebAssembly虚拟机加载并运行,加载和执行是细分的两个过程。wasm字节码加载到虚拟机,包括解码wasm字节码并将解码结果拷贝到受管内存中。一次加载后可以对应有多次执行,即启动多个wasm实例。常规来说,启动每个实例后创建该实例对应的线性内存。本申请中,S410~S430可以是在加载过程中完成,则这里的S440及后续的S450可以是在执行过程中完成,或者S410~S430发生于加载之后和启动wasm实例之前,S440和S450发生于启动wasm每个实例之后。
内存映射(memory map,mmap)是一种文件映射到内存的方法,即将一个文件或者其他对象映射到进程的虚拟地址空间的内存中,实现文件地址和进程操作的一段虚拟内存的一一映射关系。通过mmap将文件映射到虚拟内存中,然后通过对映射区的虚拟内存进行读写操作,其效果等同于对文件进行读写操作。实现这样的映射关系后,进程例如可以采用指针的方式读写操作这一段虚拟内存,而系统会自动回写脏页面到对应的文件中,即完成了对文件的操作,而不必再调用read、write等系统调用函数。
具体来说,如图6所示,用户态的一个进程启动后开辟了该进程的内存空间,该内存空间是虚拟内存空间。以C/C++程序为例,一个C/C++程序启动后,该程序的进程在内存中开辟的虚拟内存,布局可以包括从低地址到高地址的代码区、全局区、堆区、栈区,其中:
·代码区:存放函数体的二进制代码,由操作系统进行管理;
·全局区:存放全局变量和静态变量以及常量;
·栈区:由编译器自动分配释放,存放函数的参数值,局部变量等;
·堆区:由程序员在程序中指定分配和释放,若程序员未指定释放,程序结束后可以由操作系统回收。
程序一般在执行前生成代码区、全局区;程序执行后,生成栈区、堆区。具体的,程序在没有运行之前,也就是说程序没有被加载到内存前,可执行程序内部已经分好三段信息,分别是代码区、数据区和未初始化数据区(bss,图中未示出)三个部分。程序在加载到内存前,代码区和全局区(包括data段和bss段)的大小是固定的,程序运行期间不能改变。data段和bss区中的数据的生存周期一般为整个程序的运行过程。运行可执行程序,系统把程序加载到内存,除了根据可执行程序的信息分出代码区、数据区和未初始化数据区之外,还额外增加了栈区和堆区。
代码区存放CPU执行的机器指令,即程序汇编而成的二进制代码。代码区一般是共享的,对于频繁执行的程序,内存中只需要保存一份即可。且代码区一般是只读的,原因在于防止程序意外修改其中的指令。全局区包括全局变量和静态变量、常量。静态变量通常通过static关键字修饰;常量包括字符串常量和const修饰的全局变量。
C中主要用malloc开辟堆区内存,用free函数释放。C++中主要用new开辟堆区内存,用delete释放堆区内存。
栈区和堆区的虚拟内存占用是可以随着程序的运行而可变的。图6中,栈区下面的虚线表示该栈区从高地址开始可以向下生长,堆区上面的虚线表示该堆区可以从低地址向高地址方向生长。“内存文件映射”一般位于堆区,可以通过malloc来分配该堆区的一段虚拟内存空间,例如图6中所示的开始地址到截止地址的这一段空间,这里称为虚拟内存映射区。这个操作实际上是在内核态(操作系统内核)中建立包括页表在内的虚拟映射表(图中未示出),通过该虚拟映射表将虚拟内存与物理内存进行映射。也就是说,诸如通过malloc来分配堆区的一段虚拟内存空间的操作,实际上不会分配真实的物理内存空间,因此速度很快。
需要说明的是,执行Java字节码的JVM和执行wasm字节码的wasm虚拟机,本身很多是采用C编写。因此,执行wasm字节码的虚拟机,启动后产生的wasm虚拟机进程本身,很多也是采用malloc来分配堆区的一段虚拟内存空间。
mmap的原理包括将虚拟内存空间映射到内存文件的页缓存,如图6中所示。这样,对内存文件进行读写时需要经过页缓存进行中转。
S450:通过读写创建的虚拟内存映射区来对所述内存文件进行读/写操作。
在S440的基础上,可以通过对虚拟内存映射区进行读/写操作来实现对内存文件的读/写操作。这里对读、写操作分别说明。
对于经过S410~S430的过程加载wasm字节码并创建内存文件后,启动的第1个wasm实例可以如图6所示,该wasm实例启动过程可以包括经过S440的过程创建虚拟内存映射区。那么,对于该虚拟内存映射区进行读操作,可以实现对所映射的内存文件的读操作。这个映射关系如前述所述,可以通过虚拟映射表实现。
总体来说,对于启动多个wasm实例,每个实例可以在堆区建立一段虚拟内存映射区。这里,每个实例可以是在堆区建立一段独有的虚拟内存映射区。例如对于启动第2个wasm实例的情况,可以如图7所示,则两个wasm实例在堆区可以是两段不同的虚拟内存映射区,如wasm实例1对应虚拟内存映射区1,wasm实例2对应虚拟内存映射区2。那么,不同wasm实例对相应虚拟内存映射区进行读操作,可以实现对所映射的内存文件的读操作。这里尽管在虚拟内存的堆区创建了两个虚拟内存映射区,如前所述是在内核态中的虚拟映射表中建立虚拟内存与物理内存之间的映射,实际上不会分配真实的物理内存空间,因此速度很快。这里启动两个wasm实例的情况,显然可以推广到多个wasm实例的情况,对应wasm字节码一次加载多次执行的情况。每次启动一个wasm实例,带来的开销是很小的,特别是对于一次加载多次执行的情况,相对于每次执行时都从受管内存中拷贝数据段内容填充到线性内存的方式,本实施例的方式在时间方面的开销能够大大降低。
执行加载后的wasm字节码,大多时候伴随有写操作,以下结合图8和图9加以说明。图8是启动一个wasm实例的情况,当产生对虚拟内存映射区中某个地址的首次写操作时,可以触发Linux系统的缺页中断机制,给虚拟内存空间自动分配一块真实物理内存空间,并从内存文件的对应位置拷贝将被修改的内存块的数据到新的物理内存空间,该新的物理内存空间即如图8中所示的“写操作产生的内存”。该机制也称为写时复制机制,数据复制方向如图8中所示。该缺页中断机制中自动分配的一块真实物理内存的大小,可以是操作系统管理的一个物理内存页的大小,在Linux中例如为2KB。该写时复制创建的物理内存一般较小,拷贝的数据量也较小,因此尽管产生一定的时间开销,该开销也相对较小,整体上也明显优于原有方式。
进而,可以在虚拟内存映射区执行写操作。基于上述缺页中断(也称缺页异常)和写时复制机制,在虚拟内存映射区的某个地址首次执行的写操作映射到新的物理内存空间中的地址,并可以在拷贝至新的物理内存的基础上执行写操作。其中,写时复制机制确保了写操作的正确性。缺页中断机制确保了内核态中的虚拟映射表记录了虚拟内存映射区发生写操作的虚拟地址与物理内存中新创建的内存空间地址的映射关系,因此,后续对该产生写操作的虚拟内存地址的读操作,会正确的映射到的新创建的内存空间地址上,从而保证读取到的是写入后的新数据。类似的,后续对该产生写操作的虚拟内存地址的写操作,会正确的映射到的该新创建的内存空间地址上,从而保证再次写的数据是基于正确的数据所产生的写操作,即保证读/写结果的正确性。
以下以一个WASM程序例子来描述:
(
(func$func1
(i32.store(i32.const 1000)(i32.const 123));;给线性内存中1000位置写入123
(i32.store(i32.const 1001)(i32.const 123));;给线性内存中1001位置写入123
...
(i32.store(i32.const 1127)(i32.const 123));;给线性内存中1127位置写入123
);;end of func1
(memory 1);;声明本字节码用到1个线性内存
(data(i32.const 0)"长65536的字节数组,即64KB大小的初始数据段")
(export"func1"(func$func1));;让func1可以被外部调用
)
这个例子中有64KB大小的数据段,作为执行之前的线性内存的初始数据,然后执行func1函数时会对线性内存中1000位置开始的128+3(最后一个i32.store写了1127位置开始的4个字节)=132个字节进行写入数据.
在使用本方案前,每次实例化并执行func1函数过程,虚拟机会做以下事情:
1.malloc分配64KB大小的内存作为线性内存空间(有内存分配的时间开销)
2.复制这个WASM模块中的数据段(本例中是64KB大小)的数据到新分配的线性内存(有几千次的循环,以及64KB的内存复制的时间开销)
3.执行func1函数,其中会对线性内存做128次写4字节的写操作
4.结束运行,返回
使用本方案后,这个过程变为如下步骤:
1.使用加载阶段创建的64KB大小的内存文件1,使用mmap系统调用创建一段64KB的虚拟内存空间(不真实分配,时间开销极小)
2.执行func1函数,其中对线性内存1000位置第一次写的时候,线性内存的虚拟内存空间因为没有分配这个地址的真实内存空间,会触发一次缺页中断,分配1页=2KB的物理内存映射到1000开始的这块虚拟内存空间,然后继续进行在物理内存上的写操作(时间开销为分配2KB物理内存+一次写4字节的写开销)
3.继续执行func1函数后续指令,对从1001地址开始的线性内存的写指令的时候,因为线性内存从1000位置开始的2KB内存空间已经有分配物理内存,可以正常执行写操作(127次4字节的写操作)
4.结束运行,返回
可以看出,本例中的执行阶段的时间开销,从使用本方案前的:
分配64KB内存空间时间+循环复制64KB内存+128次写4字节内存——的时间开销,
使用本方案后优化为:
分配2KB内存空间时间+128次写4字节内存——的时间开销,显著缩短了执行时间。
图9为执行两个wasm实例并且都有写操作产生的情况。如图9所示,假设加载wasm字节码后,wasm实例1先执行,wasm实例2后启动。则加载环节如前述所述产生内存文件,执行wasm实例1时,采用内存映射技术基于所述内存文件创建一段虚拟内存映射区——虚拟内存映射区1,执行wasm实例2时,采用内存映射技术基于所述内存文件创建一段虚拟内存映射区——虚拟内存映射区2。
在执行过程中,对于wasm实例1中的某个地址首次产生写操作时,触发缺页中断机制,给虚拟内存空间自动分配一块真实物理内存空间,并从内存文件的对应位置拷贝将被修改的内存块的数据到新的物理内存空间,这里该新的物理内存空间即如图9中所示的“wasm实例1写操作产生的内存”。进而,虚拟内存映射区执行写操作,基于上述缺页中断和写时复制机制,在虚拟内存映射区的该地址首次执行的写操作映射到新创建的物理内存空间中的地址——“wasm实例1写操作产生的内存”中的相应地址,并可以在拷贝至新的物理内存的基础上执行写操作。后续,如果是对该产生写操作的虚拟内存地址的读操作,会正确的映射到的新创建的内存空间地址上,从而保证读取到的是写入后的新数据。类似的,后续对该产生写操作的虚拟内存地址的写操作,会正确的映射到的该新创建的内存空间地址上,从而保证再次写的数据是基于正确的数据所产生的写操作,即保证读/写结果的正确性。当然,如果后续是对未产生写操作的原有虚拟内存地址的读操作,根据虚拟映射表中的映射,也可以正确的映射到内存文件的相应地址上,从而保证读到正确的数据。
类似的,在执行过程中,对于wasm实例2中的某个地址首次产生写操作时,触发缺页中断机制,给虚拟内存空间自动分配一块真实物理内存空间,并从内存文件的对应位置拷贝将被修改的内存块的数据到新的物理内存空间,这里该新的物理内存空间即如图9中所示的“wasm实例2写操作产生的内存”。进而,虚拟内存映射区执行写操作,基于上述缺页中断和写时复制机制,在虚拟内存映射区的该地址首次执行的写操作映射到新创建的物理内存空间中的地址——“wasm实例2写操作产生的内存”中的相应地址,并可以在拷贝至新的物理内存的基础上执行写操作。后续,如果是对该产生写操作的虚拟内存地址的读操作,会正确的映射到的新创建的内存空间地址上,从而保证读取到的是写入后的新数据。类似的,后续对该产生写操作的虚拟内存地址的写操作,会正确的映射到的该新创建的内存空间地址上,从而保证再次写的数据是基于正确的数据所产生的写操作,即保证读/写结果的正确性。当然,如果后续是对未产生写操作的原有虚拟内存地址的读操作,根据虚拟映射表中的映射,也可以正确的映射到内存文件的相应地址上,并且是与wasm实例1相同的内存文件的相应地址上,从而保证读到正确数据的同时,并且不会重复复制,从而降低时间开销。
前述提到,wasm程序一次加载后可以对应有多次执行。本申请特别是对于这种一次加载多次执行的情况,可以大大降低时间方面的开销。
上述方案,可以适用于解释执行,也可以适用于JIT执行。为了尽可能的兼顾跨平台可移植性和高性能,即时编译器(Just-In-Time Compiler,JIT)的概念被提出。JIT的核心思想是“如何高效避免解释指令的重复工作”。计算机程序中存在大量重复执行的代码,比如某些计算“函数”在一个程序执行过程中可能被循环调用了很多次。如果是解释执行,则循环过程的每次执行都要对这个函数进行字节码到机器码的翻译。然而实际情况是,这个函数在几十次的翻译中产生的机器码都是完全一样的。很自然的,在第一次翻译后,将翻译好的函数的机器码缓存下来,后续再次执行的过程中,不需要再次翻译,而是直接使用缓存好的代码,这样可以提高执行效率。
相反的,有些函数在程序运行周期过程中只执行了一次(比如启动初始化),那么这类函数就不需要缓存,直接解释执行一次即可。因此JIT技术中一个核心的模块就是“热点分析”,即通过程序执行过程中分析出哪些代码执行了多次,从而对其翻译后的机器码进行缓存。对于执行次数较少的操作,不需要进行缓存。这样可以在执行效率和内存开销上达到平衡。
此外,JIT技术中的另一个核心的模块是编译优化(或称为优化编译)。直接翻译的机器码,没有结合上下文进行优化,仅仅是将高频的机器码缓存下来,性能提升有限。如果要获得更好的性能,可以对编译器进行进一步的优化。编译优化的方式,一般需要相对更多的时间来实现。
JIT的工作原理例如图10中所示。wasm源代码经过编译器编译后生成一段wasm字节码,经过热点分析后被分发到两个执行路径上(JIT Compiler和Interpreter)。被判断为热点(高频执行)的代码经JIT compiler中进行编译得到机器码,缓存并执行,一般是由CPU在操作系统(Operating System,OS)的控制下执行。低频的可以进入解释器(Interpreter),翻译成机器码后由CPU在OS的控制下执行。
以下介绍本申请一种计算机设备实施例,包括:
处理器;
以及存储器,其中存储有程序,其中在所述处理器执行所述程序时,进行以下操作:
加载wasm字节码并解析,得到wasm模块对象;根据解析得到的wasm模块对象创建线性内存并填充线性内存;创建内存文件,并将所述线性内存中的数据写入到该内存文件中;
启动每个wasm实例后:
采用内存映射技术基于所述内存文件创建一段虚拟内存映射区;
通过读/写创建的虚拟内存映射区来对所述内存文件进行读/写操作。。
以下介绍一种存储介质,用于存储程序,其中所述程序在被执行时进行以下操作:
加载wasm字节码并解析,得到wasm模块对象;根据解析得到的wasm模块对象创建线性内存并填充线性内存;创建内存文件,并将所述线性内存中的数据写入到该内存文件中;
启动每个wasm实例后:
采用内存映射技术基于所述内存文件创建一段虚拟内存映射区;
通过读/写创建的虚拟内存映射区来对所述内存文件进行读/写操作。
本申请还提供一种进一步的优化方案,如图11所示,包括:
S1110:加载wasm字节码并解析,得到wasm模块对象。
S1120:根据解析得到的wasm模块对象创建线性内存并填充线性内存。
S1130:创建内存文件,并将预设数量的所述线性内存中的数据写入到该内存文件中。
与S430不同,本方案中此处可以将预设数量的所述线性内存中的数据写入到该内存文件中,如图12中所示。例如创建n个虚拟内存映射区,n即为预设数量。可以根据wasm实例的启动数量来设置n值的大小。特别是在一些热点的wasm程序中,可以将n值设置的大一些。例如区块链中热点的wasm合约,可能调用该wasm合约的次数比较多,则n值可以设置的较大。当然,也可以给定n为一个默认值。这里,线性内存1、线性内存2、…、线性内存n可以是基于同一wasm模块对象创建并填充的线性内存,相当于同一线性内存的n个拷贝。
S1140:采用内存映射技术基于所述内存文件创建预设数量的虚拟内存映射区。
与S440不同的,本方案中此处可以创建预设数量的虚拟内存映射区,仍然如图12中所示。根据内存文件创建预设数量的虚拟内存映射区,相当于在虚拟内存中创建了n个分别到物理内存中内存文件的线性内存的一一映射。
本步骤是在一次mmap过程中完成虚拟内存映射区的创建。图4实施例中相当于每启动一个wasm实例时执行一次mmap过程,则启动n个wasm实例需要总计需要执行n次mmap过程。每次的mmap都会涉及系统调用、用户态到内核态的切换以及对内核态中虚拟映射表的修改,产生系统资源的开销,导致时间的开销。
本步骤中在一次mmap过程中完成n个虚拟内存映射区的创建,将原本的n次mmap过程压缩为了1次,从而可以大大降低时间开销。当然,这里需要S1130中写n份线性内存到内存文件中,单次写入的数据量增大。
S1150:选择未占用的虚拟内存映射区并标记为已占用,通过读写选择的虚拟内存映射区来对所述内存文件进行读/写操作。
对于经过S1110~S1140的过程后,启动的第1个wasm实例可以如图13所示。那么,对于该虚拟内存映射区进行读操作,可以实现对所映射的内存文件的读操作。这个映射关系如前述所述,可以通过包括页表在内的虚拟映射表实现。这个虚拟映射表一般位于内核态。
总体来说,对于启动多个wasm实例,每个实例可以在堆区建立一段虚拟内存映射区。这里,每个实例可以是在堆区建立一段独有的虚拟内存映射区。例如对于启动第2个wasm实例的情况,可以如图14所示,则两个wasm实例在堆区可以是两段不同的虚拟内存映射区,如wasm实例1对应虚拟内存映射区1,wasm实例2对应虚拟内存映射区2。那么,不同wasm实例对相应虚拟内存映射区进行读操作,可以实现对所映射的内存文件的读操作。这里尽管在虚拟内存的堆区创建了两个虚拟内存映射区,如前所述是在内核态中的虚拟映射表中建立虚拟内存与物理内存之间的映射,实际上不会分配真实的物理内存空间,因此速度很快。这里启动两个wasm实例的情况,显然可以推广到多个wasm实例的情况,对应wasm字节码一次加载多次执行的情况。每次启动一个wasm实例,带来的开销是很小的,特别是对于一次加载多次执行的情况,相对于每次执行时都从受管内存中拷贝数据段内容填充到线性内存的方式,本实施例的方式在时间方面的开销能够大大降低。
前述提到,启动一个新的wasm实例后,选择未占用的虚拟内存映射区并标记为已占用。具体的,可以记录这个虚拟内存映射区的地址,进而可以通过该地址选择未占用的虚拟内存映射区,并将创建的虚拟内存映射区标记为未占用。对于启动的第1个wasm实例,可以选择虚拟内存映射区1进行对内存文件1的读/写操作,并将虚拟内存映射区1标记为已占用。对于启动的第2个wasm实例,可以选择虚拟内存映射区2进行对内存文件1的读/写操作,并将虚拟内存映射区1标记为已占用。以此类推。
也可以记录首个虚拟内存映射区的地址,在每个虚拟内存映射区的大小相同且顺序排布的情况下,相邻虚拟内存映射区间隔相同的偏移量,例如是M。例如,启动wasm2时,可以基于虚拟内存映射区1的地址+偏移量M得到虚拟内存映射区1的地址,并从该计算得到地址开始选择M大小的虚拟内存空间作为wasm实例2的虚拟内存映射区,通过读/写选择的虚拟内存映射区2来对所述内存文件进行读/写操作。而且,记录M,还可以作为标记虚拟内存映射区2为已占用。相应的,启动wasm3时,可以基于虚拟内存映射区1的地址+偏移量2M得到虚拟内存映射区2的地址,并从该计算得到地址开始选择M大小的虚拟内存空间作为wasm实例3的虚拟内存映射区,通过读/写选择的虚拟内存映射区3来对所述内存文件进行读/写操作。而且,记录2M,还可以作为标记虚拟内存映射区3为已占用。以此类推。可见,可以通过记录M个偏移量标记第M-1个虚拟内存映射区为已占用。
执行加载后的wasm字节码,大多时候伴随有写操作,以下结合图15和图16加以说明。图15是启动一个wasm实例的情况,当产生对虚拟内存映射区中某个地址的首次写操作时,可以触发Linux系统的缺页中断机制,给虚拟内存空间自动分配一块真实物理内存空间,并从内存文件的对应位置拷贝将被修改的内存块的数据到新的物理内存空间,该新的物理内存空间即如图15中所示的“wasm实例1写操作产生的内存”。该机制也称为写时复制机制,数据复制方向如图15中所示。该缺页中断机制中自动分配的一块真实物理内存的大小,可以是操作系统管理的一个物理内存页的大小,在Linux中例如为2KB。该写时复制创建的物理内存一般较小,拷贝的数据量也较小,因此尽管产生一定的时间开销,该开销也相对较小,整体上也明显优于原有方式。
进而,可以在虚拟内存映射区执行写操作。基于上述缺页中断(也称缺页异常)和写时复制机制,在虚拟内存映射区的某个地址首次执行的写操作映射到新的物理内存空间中的地址,并可以在拷贝至新的物理内存的基础上执行写操作。其中,写时复制机制确保了写操作的正确性。缺页中断机制确保了内核态中的虚拟映射表记录了虚拟内存映射区发生写操作的虚拟地址与物理内存中新创建的内存空间地址的映射关系,因此,后续对该产生写操作的虚拟内存地址的读操作,会正确的映射到的新创建的内存空间地址上,从而保证读取到的是写入后的新数据。类似的,后续对该产生写操作的虚拟内存地址的写操作,会正确的映射到的该新创建的内存空间地址上,从而保证再次写的数据是基于正确的数据所产生的写操作,即保证读/写结果的正确性。
图16为执行两个wasm实例并且都有写操作产生的情况。如图16所示,假设加载wasm字节码后,wasm实例1先执行,wasm实例2后启动。则加载环节如前述所述产生内存文件,执行wasm实例15时,选择虚拟内存映射区1,执行wasm实例2时,选择虚拟内存映射区2。
在执行过程中,对于wasm实例1中的某个地址首次产生写操作时,触发缺页中断机制,给虚拟内存空间自动分配一块真实物理内存空间,并从内存文件的对应位置拷贝将被修改的内存块的数据到新的物理内存空间,这里该新的物理内存空间即如图16中所示的“wasm实例1写操作产生的内存”。进而,虚拟内存映射区执行写操作,基于上述缺页中断和写时复制机制,在虚拟内存映射区的该地址首次执行的写操作映射到新创建的物理内存空间中的地址——“wasm实例1写操作产生的内存”中的相应地址,并可以在拷贝至新的物理内存的基础上执行写操作。后续,如果是对该产生写操作的虚拟内存地址的读操作,会正确的映射到的新创建的内存空间地址上,从而保证读取到的是写入后的新数据。类似的,后续对该产生写操作的虚拟内存地址的写操作,会正确的映射到的该新创建的内存空间地址上,从而保证再次写的数据是基于正确的数据所产生的写操作,即保证读/写结果的正确性。当然,如果后续是对未产生写操作的原有虚拟内存地址的读操作,根据虚拟映射表中的映射,也可以正确的映射到内存文件的相应地址上,从而保证读到正确的数据。
类似的,在执行过程中,对于wasm实例2中的某个地址首次产生写操作时,触发缺页中断机制,给虚拟内存空间自动分配一块真实物理内存空间,并从内存文件的对应位置拷贝将被修改的内存块的数据到新的物理内存空间,这里该新的物理内存空间即如图16中所示的“wasm实例2写操作产生的内存”。进而,虚拟内存映射区执行写操作,基于上述缺页中断和写时复制机制,在虚拟内存映射区的该地址首次执行的写操作映射到新创建的物理内存空间中的地址——“wasm实例2写操作产生的内存”中的相应地址,并可以在拷贝至新的物理内存的基础上执行写操作。后续,如果是对该产生写操作的虚拟内存地址的读操作,会正确的映射到的新创建的内存空间地址上,从而保证读取到的是写入后的新数据。类似的,后续对该产生写操作的虚拟内存地址的写操作,会正确的映射到的该新创建的内存空间地址上,从而保证再次写的数据是基于正确的数据所产生的写操作,即保证读/写结果的正确性。\
此外,首次采用内存映射技术基于所述内存文件创建预设数量的虚拟内存映射区,被占用完毕后,可以再次采用内存映射技术基于所述内存文件创建预设数量的虚拟内存映射区,以供后续新启动的wasm实例选择并占用,进而通过读/写选择的虚拟内存映射区来对所述内存文件进行读/写操作。如图17所示,特别是其中标示出的首次分配和二次分配,不再赘述。
以下介绍本申请一种计算机设备实施例,包括:
处理器;
以及存储器,其中存储有程序,其中在所述处理器执行所述程序时,进行以下操作:
加载wasm字节码并解析,得到wasm模块对象;根据解析得到的wasm模块对象创建线性内存并填充线性内存;创建内存文件,并将所述线性内存中的数据写入到该内存文件中;采用内存映射技术基于所述内存文件创建预设数量的虚拟内存映射区;
启动每个wasm实例后:
选择未占用的虚拟内存映射区并标记为已占用,通过读/写选择的虚拟内存映射区来对所述内存文件进行读/写操作。
以下介绍一种存储介质,用于存储程序,其中所述程序在被执行时进行以下操作:
加载wasm字节码并解析,得到wasm模块对象;根据解析得到的wasm模块对象创建线性内存并填充线性内存;创建内存文件,并将所述线性内存中的数据写入到该内存文件中;采用内存映射技术基于所述内存文件创建预设数量的虚拟内存映射区;
启动每个wasm实例后:
选择未占用的虚拟内存映射区并标记为已占用,通过读/写选择的虚拟内存映射区来对所述内存文件进行读/写操作。
在20世纪90年代,对于一个技术的改进可以很明显地区分是硬件上的改进(例如,对二极管、晶体管、开关等电路结构的改进)还是软件上的改进(对于方法流程的改进)。然而,随着技术的发展,当今的很多方法流程的改进已经可以视为硬件电路结构的直接改进。设计人员几乎都通过将改进的方法流程编程到硬件电路中来得到相应的硬件电路结构。因此,不能说一个方法流程的改进就不能用硬件实体模块来实现。例如,可编程逻辑器件(Programmable Logic Device,PLD)(例如现场可编程门阵列(Field Programmable GateArray,FPGA))就是这样一种集成电路,其逻辑功能由用户对器件编程来确定。由设计人员自行编程来把一个数字系统“集成”在一片PLD上,而不需要请芯片制造厂商来设计和制作专用的集成电路芯片。而且,如今,取代手工地制作集成电路芯片,这种编程也多半改用“逻辑编译器(logic compiler)”软件来实现,它与程序开发撰写时所用的软件编译器相类似,而要编译之前的原始代码也得用特定的编程语言来撰写,此称之为硬件描述语言(Hardware Description Language,HDL),而HDL也并非仅有一种,而是有许多种,如ABEL(Advanced Boolean Expression Language)、AHDL(Altera Hardware DescriptionLanguage)、Confluence、CUPL(Cornell University Programming Language)、HDCal、JHDL(Java Hardware Description Language)、Lava、Lola、MyHDL、PALASM、RHDL(RubyHardware Description Language)等,目前最普遍使用的是VHDL(Very-High-SpeedIntegrated Circuit Hardware Description Language)与Verilog。本领域技术人员也应该清楚,只需要将方法流程用上述几种硬件描述语言稍作逻辑编程并编程到集成电路中,就可以很容易得到实现该逻辑方法流程的硬件电路。
控制器可以按任何适当的方式实现,例如,控制器可以采取例如微处理器或处理器以及存储可由该(微)处理器执行的计算机可读程序代码(例如软件或固件)的计算机可读介质、逻辑门、开关、专用集成电路(Application Specific Integrated Circuit,ASIC)、可编程逻辑控制器和嵌入微控制器的形式,控制器的例子包括但不限于以下微控制器:ARC 625D、Atmel AT91SAM、Microchip PIC18F26K20以及Silicone Labs C8051F320,存储器控制器还可以被实现为存储器的控制逻辑的一部分。本领域技术人员也知道,除了以纯计算机可读程序代码方式实现控制器以外,完全可以通过将方法步骤进行逻辑编程来使得控制器以逻辑门、开关、专用集成电路、可编程逻辑控制器和嵌入微控制器等的形式来实现相同功能。因此这种控制器可以被认为是一种硬件部件,而对其内包括的用于实现各种功能的装置也可以视为硬件部件内的结构。或者甚至,可以将用于实现各种功能的装置视为既可以是实现方法的软件模块又可以是硬件部件内的结构。
上述实施例阐明的系统、装置、模块或单元,具体可以由计算机芯片或实体实现,或者由具有某种功能的产品来实现。一种典型的实现设备为服务器系统。当然,本申请不排除随着未来计算机技术的发展,实现上述实施例功能的计算机例如可以为个人计算机、膝上型计算机、车载人机交互设备、蜂窝电话、相机电话、智能电话、个人数字助理、媒体播放器、导航设备、电子邮件设备、游戏控制台、平板计算机、可穿戴设备或者这些设备中的任何设备的组合。
虽然本说明书一个或多个实施例提供了如实施例或流程图所述的方法操作步骤,但基于常规或者无创造性的手段可以包括更多或者更少的操作步骤。实施例中列举的步骤顺序仅仅为众多步骤执行顺序中的一种方式,不代表唯一的执行顺序。在实际中的装置或终端产品执行时,可以按照实施例或者附图所示的方法顺序执行或者并行执行(例如并行处理器或者多线程处理的环境,甚至为分布式数据处理环境)。术语“包括”、“包含”或者其任何其他变体意在涵盖非排他性的包含,从而使得包括一系列要素的过程、方法、产品或者设备不仅包括那些要素,而且还包括没有明确列出的其他要素,或者是还包括为这种过程、方法、产品或者设备所固有的要素。在没有更多限制的情况下,并不排除在包括所述要素的过程、方法、产品或者设备中还存在另外的相同或等同要素。例如若使用到第一,第二等词语用来表示名称,而并不表示任何特定的顺序。
为了描述的方便,描述以上装置时以功能分为各种模块分别描述。当然,在实施本说明书一个或多个时可以把各模块的功能在同一个或多个软件和/或硬件中实现,也可以将实现同一功能的模块由多个子模块或子单元的组合实现等。以上所描述的装置实施例仅仅是示意性的,例如,所述单元的划分,仅仅为一种逻辑功能划分,实际实现时可以有另外的划分方式,例如多个单元或组件可以结合或者可以集成到另一个系统,或一些特征可以忽略,或不执行。另一点,所显示或讨论的相互之间的耦合或直接耦合或通信连接可以是通过一些接口,装置或单元的间接耦合或通信连接,可以是电性,机械或其它的形式。
本发明是参照根据本发明实施例的方法、装置(系统)、和计算机程序产品的流程图和/或方框图来描述的。应理解可由计算机程序指令实现流程图和/或方框图中的每一流程和/或方框、以及流程图和/或方框图中的流程和/或方框的结合。可提供这些计算机程序指令到通用计算机、专用计算机、嵌入式处理机或其他可编程数据处理设备的处理器以产生一个机器,使得通过计算机或其他可编程数据处理设备的处理器执行的指令产生用于实现在流程图一个流程或多个流程和/或方框图一个方框或多个方框中指定的功能的装置。
这些计算机程序指令也可存储在能引导计算机或其他可编程数据处理设备以特定方式工作的计算机可读存储器中,使得存储在该计算机可读存储器中的指令产生包括指令装置的制造品,该指令装置实现在流程图一个流程或多个流程和/或方框图一个方框或多个方框中指定的功能。
这些计算机程序指令也可装载到计算机或其他可编程数据处理设备上,使得在计算机或其他可编程设备上执行一系列操作步骤以产生计算机实现的处理,从而在计算机或其他可编程设备上执行的指令提供用于实现在流程图一个流程或多个流程和/或方框图一个方框或多个方框中指定的功能的步骤。
在一个典型的配置中,计算设备包括一个或多个处理器(CPU)、输入/输出接口、网络接口和内存。
内存可能包括计算机可读介质中的非永久性存储器,随机存取存储器(RAM)和/或非易失性内存等形式,如只读存储器(ROM)或闪存(flash RAM)。内存是计算机可读介质的示例。
计算机可读介质包括永久性和非永久性、可移动和非可移动媒体可以由任何方法或技术来实现信息存储。信息可以是计算机可读指令、数据结构、程序的模块或其他数据。计算机的存储介质的例子包括,但不限于相变内存(PRAM)、静态随机存取存储器(SRAM)、动态随机存取存储器(DRAM)、其他类型的随机存取存储器(RAM)、只读存储器(ROM)、电可擦除可编程只读存储器(EEPROM)、快闪记忆体或其他内存技术、只读光盘只读存储器(CD-ROM)、数字多功能光盘(DVD)或其他光学存储、磁盒式磁带,磁带磁磁盘存储、石墨烯存储或其他磁性存储设备或任何其他非传输介质,可用于存储可以被计算设备访问的信息。按照本文中的界定,计算机可读介质不包括暂存电脑可读媒体(transitory media),如调制的数据信号和载波。
本领域技术人员应明白,本说明书一个或多个实施例可提供为方法、系统或计算机程序产品。因此,本说明书一个或多个实施例可采用完全硬件实施例、完全软件实施例或结合软件和硬件方面的实施例的形式。而且,本说明书一个或多个实施例可采用在一个或多个其中包含有计算机可用程序代码的计算机可用存储介质(包括但不限于磁盘存储器、CD-ROM、光学存储器等)上实施的计算机程序产品的形式。
本说明书一个或多个实施例可以在由计算机执行的计算机可执行指令的一般上下文中描述,例如程序模块。一般地,程序模块包括执行特定任务或实现特定抽象数据类型的例程、程序、对象、组件、数据结构等等。也可以在分布式计算环境中实践本本说明书一个或多个实施例,在这些分布式计算环境中,由通过通信网络而被连接的远程处理设备来执行任务。在分布式计算环境中,程序模块可以位于包括存储设备在内的本地和远程计算机存储介质中。
本说明书中的各个实施例均采用递进的方式描述,各个实施例之间相同相似的部分互相参见即可,每个实施例重点说明的都是与其他实施例的不同之处。尤其,对于系统实施例而言,由于其基本相似于方法实施例,所以描述的比较简单,相关之处参见方法实施例的部分说明即可。在本说明书的描述中,参考术语“一个实施例”、“一些实施例”、“示例”、“具体示例”、或“一些示例”等的描述意指结合该实施例或示例描述的具体特征、结构、材料或者特点包含于本说明书的至少一个实施例或示例中。在本说明书中,对上述术语的示意性表述不必须针对的是相同的实施例或示例。而且,描述的具体特征、结构、材料或者特点可以在任一个或多个实施例或示例中以合适的方式结合。此外,在不相互矛盾的情况下,本领域的技术人员可以将本说明书中描述的不同实施例或示例以及不同实施例或示例的特征进行结合和组合。
以上所述仅为本说明书一个或多个实施例的实施例而已,并不用于限制本本说明书一个或多个实施例。对于本领域技术人员来说,本说明书一个或多个实施例可以有各种更改和变化。凡在本说明书的精神和原理之内所作的任何修改、等同替换、改进等,均应包含在权利要求范围之内。
Claims (10)
1.一种启动WebAssembly程序的方法,包括:
加载wasm字节码并解析,得到wasm模块对象;根据解析得到的wasm模块对象创建线性内存并填充线性内存;创建内存文件,并将所述线性内存中的数据写入到该内存文件中;采用内存映射技术基于所述内存文件创建预设数量的虚拟内存映射区;
启动每个wasm实例后:
选择未占用的虚拟内存映射区并标记为已占用,通过读/写选择的虚拟内存映射区来对所述内存文件进行读/写操作。
2.如权利要求1所述的方法,在对创建的虚拟内存映射区执行首次写操作时,给虚拟内存空间分配一块真实物理内存空间,并从内存文件的对应位置拷贝将被修改的内存块的数据到所述分配的物理内存空间。
3.如权利要求2所述的方法,后续对该首次写操作的虚拟内存地址的读或写操作,映射到所述新分配的物理内存空间。
4.如权利要求2或3所述的方法,所述分配的一块真实物理内存空间为操作系统管理的一个物理内存页大小。
5.如权利要求1所述的方法,所述选择未占用的虚拟内存映射区并标记为已占用,包括:
虚拟内存映射区记录有地址,通过该地址选择未占用的虚拟内存映射区,并将创建的虚拟内存映射区标记为未占用。
6.如权利要求1所述的方法,虚拟内存中记录首个虚拟内存映射区的地址,在每个虚拟内存映射区的大小相同且顺序排布的情况下,相邻虚拟内存映射区间隔相同的偏移量;
所述选择未占用的虚拟内存映射区并标记为已占用,包括:
基于首个虚拟内存映射区的地址和偏移量得到所要占用的虚拟内存映射区的地址。
7.如权利要求1所述的方法,所述标记为已占用包括:
通过记录M个偏移量标记第M-1个虚拟内存映射区为已占用。
8.如权利要求1所述的方法,所述采用内存映射技术基于所述内存文件创建预设数量的虚拟内存映射区,被占用完毕后,再次采用内存映射技术基于所述内存文件创建预设数量的虚拟内存映射区,以供后续新启动的wasm实例选择并占用。
9.一种计算机设备,包括:
处理器;
以及存储器,其中存储有程序,其中在所述处理器执行所述程序时,进行以下操作:
加载wasm字节码并解析,得到wasm模块对象;根据解析得到的wasm模块对象创建线性内存并填充线性内存;创建内存文件,并将所述线性内存中的数据写入到该内存文件中;采用内存映射技术基于所述内存文件创建预设数量的虚拟内存映射区;
启动每个wasm实例后:
选择未占用的虚拟内存映射区并标记为已占用,通过读/写选择的虚拟内存映射区来对所述内存文件进行读/写操作。
10.一种存储介质,用于存储程序,其中所述程序在被执行时进行以下操作:
加载wasm字节码并解析,得到wasm模块对象;根据解析得到的wasm模块对象创建线性内存并填充线性内存;创建内存文件,并将所述线性内存中的数据写入到该内存文件中;采用内存映射技术基于所述内存文件创建预设数量的虚拟内存映射区;
启动每个wasm实例后:
选择未占用的虚拟内存映射区并标记为已占用,通过读/写选择的虚拟内存映射区来对所述内存文件进行读/写操作。
Priority Applications (1)
Application Number | Priority Date | Filing Date | Title |
---|---|---|---|
CN202310918129.XA CN116932085A (zh) | 2023-07-24 | 2023-07-24 | 一种启动WebAssembly程序的方法、计算机设备及存储介质 |
Applications Claiming Priority (1)
Application Number | Priority Date | Filing Date | Title |
---|---|---|---|
CN202310918129.XA CN116932085A (zh) | 2023-07-24 | 2023-07-24 | 一种启动WebAssembly程序的方法、计算机设备及存储介质 |
Publications (1)
Publication Number | Publication Date |
---|---|
CN116932085A true CN116932085A (zh) | 2023-10-24 |
Family
ID=88378735
Family Applications (1)
Application Number | Title | Priority Date | Filing Date |
---|---|---|---|
CN202310918129.XA Pending CN116932085A (zh) | 2023-07-24 | 2023-07-24 | 一种启动WebAssembly程序的方法、计算机设备及存储介质 |
Country Status (1)
Country | Link |
---|---|
CN (1) | CN116932085A (zh) |
-
2023
- 2023-07-24 CN CN202310918129.XA patent/CN116932085A/zh active Pending
Similar Documents
Publication | Publication Date | Title |
---|---|---|
CN111770113B (zh) | 一种执行智能合约的方法、区块链节点和节点设备 | |
CN111399990B (zh) | 解释执行智能合约指令的方法及装置 | |
KR100712767B1 (ko) | 컴파일된 코드에서 동적 클래스 초기화 검사의 비용을 줄이기 위한 컴퓨터 시스템의 명령어 컴파일 방법 및 그 컴퓨터 판독가능 매체 | |
US7353504B2 (en) | System and method for efficiently generating native code calls from byte code in virtual machines | |
JP2004280795A (ja) | エクストリームパイプライン及び最適化再配列技術 | |
WO2024045379A1 (zh) | 编译方法和编译器、Wasm虚拟机 | |
CN111770204B (zh) | 一种执行智能合约的方法、区块链节点和存储介质 | |
CN111815310B (zh) | 一种执行智能合约的方法、区块链节点和存储介质 | |
CN111768183B (zh) | 一种执行智能合约的方法、区块链节点和存储介质 | |
CN106909441B (zh) | 一种基于jvm的磁盘直接i/o访问的方法 | |
CN111770116B (zh) | 一种执行智能合约的方法、区块链节点、存储介质 | |
EP1283465A2 (en) | Transforming & caching computer programs | |
CN111768184A (zh) | 一种执行智能合约的方法及区块链节点 | |
US20040083467A1 (en) | System and method for executing intermediate code | |
CN111770202B (zh) | 一种执行智能合约的方法、区块链节点和存储介质 | |
CN116934330A (zh) | 一种调用智能合约的方法及执行方法、计算机设备及存储介质 | |
JP5401561B2 (ja) | クラスファイル内にネイティブコードを埋め込むことによる仮想メカニズム内でのプラットフォーム依存ルーチンの適用 | |
US20240231864A9 (en) | Hybrid just in time load module compiler with performance optimizations | |
CN115543331A (zh) | 虚拟线性内存的硬件、软件协同扩展方法及电子设备 | |
CN116932085A (zh) | 一种启动WebAssembly程序的方法、计算机设备及存储介质 | |
CN116909652A (zh) | 一种启动WebAssembly程序的方法、计算机设备及存储介质 | |
KR100478463B1 (ko) | 응용 프로그램의 동적링크 방법 | |
CN116931947A (zh) | 一种优化wasm字节码的方法及执行方法、计算机设备及存储介质 | |
KR100763199B1 (ko) | 가상 머신 환경에서의 메소드 호출 방법 및 상기 방법을수행하는 가상 머신이 탑재된 시스템 | |
CN116931949A (zh) | 一种优化wasm字节码的方法及执行方法、计算机设备及存储介质 |
Legal Events
Date | Code | Title | Description |
---|---|---|---|
PB01 | Publication | ||
PB01 | Publication | ||
SE01 | Entry into force of request for substantive examination | ||
SE01 | Entry into force of request for substantive examination |