- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
源链接:https://www.axa6.com/zh/an-excellent-virtual-machine-memory-architecture 。
虚拟机内存架构直接影响虚拟机的性能和占用。设计一个优秀的架构可以有效提升性能和效率。 本文将介绍AQ虚拟机使用的内存架构,以及AQ虚拟机内存的详细标准。 通过对于虚拟机内存架构的优化,有助于虚拟机的运行效率和减少占用。如果可以,应该尽可能地平衡两者,使虚拟机达到最佳状态.
在某些情况下,应该根据虚拟机的特殊需求进行不同的开发。 例如:在单片机等内存受限情况下,需要尽可能地减少占用。 而在并行计算等性能敏感情况,则需要侧重于性能优化.
AQ采取了寄存器的基础内存架构,但与标准的寄存器架构有所不同,对寄存器架构进行了部分改进和优化.
此处的寄存器并非CPU中的寄存器,而是在内存中模拟出的虚拟寄存器.
相较与JAVA、Python等主流语言虚拟机采取堆栈架构不同,AQ决定采取寄存器架构的原因是性能的优化与字节码的容易理解。 虽然堆栈架构被普遍认为更容易移植和编写,但在实际的性能中会有一些损耗,对于内存的多次访问会减缓其速度,这是不可避免并且难以彻底优化的。因此,为了解决此处的性能损耗,AQ采用了寄存器架构。同时,从字节码的角度上说,寄存器架构的字节码更容易理解,其指令类似于函数的参数方式,而不是直接面对堆栈的众多操作.
寄存器
架构的区别标准的寄存器架构中,寄存器包含:
数据类型
- 寄存器将存储的数据的类型(如int、float、double等)数据
- 寄存器将存储的数据的值尽管不同语言的虚拟机内存架构可能有所不同,但大致都存储了这些信息.
而在AQ开发过程中曾使用了该架构,但是经过测试,其存在较大的内存占用.
以下是AQ曾使用的register.h代码:
// Copyright 2024 AQ authors, All Rights Reserved.
// This program is licensed under the AQ License. You can find the AQ license in
// the root directory.
#ifndef AQ_AQVM_MEMORY_REGISTER_H_
#define AQ_AQVM_MEMORY_REGISTER_H_
#include <stdbool.h>
enum AqvmMemoryRegister_ValueType {
// TODO(Register): Waiting for the improvement of the register.
AqvmMemoryRegisterValueType_INT,
AqvmMemoryRegisterValueType_CONSTINT,
AqvmMemoryRegisterValueType_FLOAT,
AqvmMemoryRegisterValueType_CONSTFLOAT,
AqvmMemoryRegisterValueType_DOUBLE,
AqvmMemoryRegisterValueType_CONSTDOUBLE,
AqvmMemoryRegisterValueType_LONG,
AqvmMemoryRegisterValueType_CONSTLONG,
AqvmMemoryRegisterValueType_CHARACTER,
AqvmMemoryRegisterValueType_CONSTCHARACTER,
AqvmMemoryRegisterValueType_BOOLEAN,
AqvmMemoryRegisterValueType_CONSTBOOLEAN
};
union AqvmMemoryRegister_Value {
// TODO(Register): Waiting for the improvement of the register.
int int_value;
const int const_int_value;
float float_value;
const float const_float_value;
double double_value;
const double const_double_value;
long long_value;
const long const_long_value;
char character_value;
const char const_character_value;
bool boolean_value;
const bool const_boolean_value;
};
struct AqvmMemoryRegister_Register {
enum AqvmMemoryRegister_ValueType type;
union AqvmMemoryRegister_Value value;
};
#endif
从上述代码可以看出,即使仅保留了必要内容,但由于enum类型的AqvmMemoryRegister_ValueType占用4字节,union类型的AqvmMemoryRegister_Value占用8字节,struct类型本身就会占用12字节内存.
同时,由于C编译器的优化,struct类型的AqvmMemoryRegister_Register中enum类型的type为与union类型的value进行内存对齐,因此加入4字节的填充内存。使struct类型的AqvmMemoryRegister_Register占用16字节.
其中如果使用int等非8字节类型,则会有4字节的填充内存被浪费,从而造成内存损耗。因此在全部的寄存器中会有4-8字节的内存浪费.
AQ
的寄存器架构为了解决传统寄存器架构的占用问题,AQ结合了JVM的栈帧的局部变量表特点,对内存架构进行了优化,使占用问题显著减少.
以下是备选的三种方案:
// plan 1:
struct AqvmMemoryRegister_Register{
uint8_t type;
void* value_ptr;
};
void* value;
AqvmMemoryRegister_Register array[];
// plan 2:
void* value;
// value to the memory address of index 0 is int, the index 0 to the index 1 is
// float, etc.
size_t type[];
// plan 3:
struct AqvmMemoryRegister_Register {
uint32_t* value;
size_t size;
};
由于指针占用4-8字节,数据本身占用1-8字节,加上类型1字节,因此plan 1占用6-17字节,同时可能会存在内存对齐,因此plan 1同样会造成极大的内存损失。 事实上,在要求保留内存类型信息时,内存利用率最高的是plan 2,但plan 2不能保存在同一数据结构(如:结构体)中不同类型数据的连贯性,可能会使部分指针操作失效。因此为了内存安全,不使用plan 2。 在某些情况下(虚拟机指令集包括类型),plan 3也可以满足内存存储的需要,但由于精简指令集的需要,没有在指令中包含类型信息,因此无法满足虚拟机运行需要.
因此我们采取如下设计,保证对于内存的利用率,同时使内存占用问题有了很大改善.
AQ的内存直接使用void*指针存储数据,size_t存储占用内存大小,并且使用uint8_t数组存储类型。由于uint8_t占用8位,为减少占用,每个字节使用4位来存储类型。因此,一个uint8_t变量可以存储2个类型。每个uint8_t变量的前4位用于偶数字节的类型,后4位用于奇数字节的类型.
// The struct stores information about the memory.
// |type| is a pointer to an array that stores the type of each byte in the
// memory. Each byte uses 4 bits to store the type. So a uint8_t variable can
// store 2 types. Each uint8_t variable's first 4 bits are used for the even
// byte's type and the next 4 bits are used for the odd byte's type. The type
// list is in types.h.
// |data| is a pointer of type void* to the memory that stores the data.
// |size| is the size of the memory.
// NOTICE: The struct AqvmMemory_Memory only stores information of the memory.
// The memory is allocated by the bytecode function when storing the bytecode.
// The memory of |memory| and |type| is part of the bytecode memory.
struct AqvmMemory_Memory {
uint8_t* type;
void* data;
size_t size;
};
由于内存的原因,对于type的存取需要精确的利用。uint8_t类型需要8位,但是超过了类型的存储需要,因此4位既可以满足对于类型的存储需要,同时又可以减少内存占用。但是需要特殊的函数维持type的存取.
// Sets the type of the data at |index| bytes in |memory| to |type|. |type|
// should be less than 4 bits.
// Returns 0 if successful. Returns -1 if the memory pointer is NULL. Returns -2
// if the type pointer is NULL. Returns -3 if the index is out of range. Returns
// -4 if the type is out of range.
int AqvmMemory_SetType(const struct AqvmMemory_Memory* memory, size_t index,
uint8_t type) {
if (memory == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_SetType_NullMemoryPointer\"",
"\"The memory pointer is NULL.\"", NULL);
return -1;
}
if (memory->type == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_SetType_NullTypePointer\"",
"\"The type pointer is NULL.\"", NULL);
return -2;
}
if (index > memory->size) {
AqvmRuntimeDebugger_OutputReport(
"\"ERROR\"", "\"AqvmMemory_SetType_OutOfMemoryRange\"",
"\"The index is out of memory range.\"", NULL);
return -3;
}
if (type > 0x0F) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_SetType_OutOfTypeRange\"",
"\"The type is out of range.\"", NULL);
return -4;
}
// Sets the type of the data at |index| bytes in memory.
// Since Aqvm stores type data occupying 4 bits and uint8_t occupying 8 bits,
// each uint8_t type location stores two type data. The storage locations
// (high 4 bits, low 4 bits) are set according to the parity of |index|. Even
// numbers are stored in the high bits of (|index| / 2) and odd numbers are
// stored in the low bits of (|index| / 2).
if (index % 2 != 0) {
memory->type[index / 2] = (memory->type[index / 2] & 0xF0) | type;
} else {
memory->type[index / 2] = (memory->type[index / 2] & 0x0F) | (type << 4);
}
return 0;
}
// Gets the type of the data at |index| bytes in |memory|.
// Returns the type that is less than 4 bits (0X0F) if successful. Returns 0x11
// if the memory pointer is NULL. Returns 0x12 if the type pointer is NULL.
// Returns 0x13 if the index is out of memory range.
uint8_t AqvmMemory_GetType(struct AqvmMemory_Memory* memory, size_t index) {
if (memory == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_GetType_NullMemoryPointer\"",
"\"The memory pointer is NULL.\"", NULL);
return 0x11;
}
if (memory->type == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_GetType_NullTypePointer\"",
"\"The type pointer is NULL.\"", NULL);
return 0x12;
}
if (index > memory->size) {
AqvmRuntimeDebugger_OutputReport(
"\"ERROR\"", "\"AqvmMemory_GetType_OutOfMemoryRange\"",
"\"The index is out of memory range.\"", NULL);
return 0x13;
}
// Gets the type of the data at |index| bytes in memory.
// Since Aqvm stores type data occupying 4 bits and uint8_t occupying 8 bits,
// each uint8_t type location stores two type data. The storage locations
// (high 4 bits, low 4 bits) are set according to the parity of |index|. Even
// numbers are stored in the high bits of (|index| / 2) and odd numbers are
// stored in the low bits of (|index| / 2).
if (index % 2 != 0) {
return memory->type[index / 2] & 0x0F;
} else {
return (memory->type[index / 2] & 0xF0) >> 4;
}
}
但使用该设计对于数据的存储有较高要求,因为数据的长度不固定,因此需要专门的函数配合内存进行操作.
// Writes the data that |data_ptr| points to of size |size| to the data of at
// |index| bytes in |memory|.
// Returns 0 if successful. Returns -1 if the memory pointer is NULL. Returns -2
// if the type pointer is NULL. Returns -3 if the index is out of range. Returns
// -4 if the data pointer is NULL.
int AqvmMemory_WriteData(struct AqvmMemory_Memory* memory, size_t index,
void* data_ptr, size_t size) {
if (memory == NULL) {
AqvmRuntimeDebugger_OutputReport(
"\"ERROR\"", "\"AqvmMemory_WriteData_NullMemoryPointer\"",
"\"The memory pointer is NULL.\"", NULL);
return -1;
}
if (memory->type == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_WriteData_NullTypePointer\"",
"\"The type pointer is NULL.\"", NULL);
return -2;
}
if (index > memory->size) {
AqvmRuntimeDebugger_OutputReport(
"\"ERROR\"", "\"AqvmMemory_WriteData_OutOfMemoryRange\"",
"\"The index is out of memory range.\"", NULL);
return -3;
}
if (data_ptr == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_WriteData_NullDataPointer\"",
"\"The data pointer is NULL.\"", NULL);
return -4;
}
// Since void* does not have a specific size, pointer moves need to be
// converted before moving.
memcpy((void*)((uintptr_t)memory->data + index), data_ptr, size);
return 0;
}
除了减少内存使用外,避免内存的二次占用同样重要。因此我们复用字节码的内存,将内存数据和类型存储在字节码的内存部分中,利用字节码文件中预先分配的内存(字节码文件中包含内存的数据和类型),实现对于内存的高效利用。 因为如果单独存储两部分,则需要有两部分重复的内存数据和类型,一份在内存部分,而另一份,字节码部分则不会被使用,因此我们采取了复用的方法,减少了因内存数据和类型而造成的内存浪费。 但因此需要特殊的函数实现,同时需要注意内存数据和类型的内存的分配和释放由字节码的相关函数进行管理.
// Creates the struct AqvmMemory_Memory with |data|, |type|, and |size|.
// The function will allocate a struct AqvmMemory_Memory and copy |data|,
// |type|, and |size| into the struct. Returns a pointer to the struct if
// successful. Returns NULL if creation fails.
struct AqvmMemory_Memory* AqvmMemory_CreateMemory(void* data, void* type,
size_t size) {
struct AqvmMemory_Memory* memory_ptr =
(struct AqvmMemory_Memory*)malloc(sizeof(struct AqvmMemory_Memory));
if (memory_ptr == NULL) {
AqvmRuntimeDebugger_OutputReport(
"\"ERROR\"", "\"AqvmMemory_CreateMemory_MemoryAllocationFailure\"",
"\"Failed to allocate memory.\"", NULL);
return NULL;
}
memory_ptr->data = data;
memory_ptr->type = type;
memory_ptr->size = size;
return memory_ptr;
}
// Free the memory of the |memory_ptr|. No return.
// NOTICE: The function only free the memory of the struct. The memory pointed
// to by pointers to data and type in struct is not freed. This memory is
// managed by bytecode related functions.
void AqvmMemory_FreeMemory(struct AqvmMemory_Memory* memory_ptr) {
free(memory_ptr);
}
除此之外,由于部分系统对于类型的定义与AQ标准有所差异,因此设计了相关函数确保虚拟机符合标准。如果系统与标准存在差异,应当为这些系统进行特殊的设计.
// Checks the memory conditions in the system.
// Returns the number of warnings.
int AqvmMemory_CheckMemoryConditions() {
int warning_count = 0;
if (sizeof(aqint) != 4) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_IntLengthWarning\"",
"\"The length requirement for the int type does not conform to the "
"type "
"definition.\"",
NULL);
++warning_count;
}
if (sizeof(aqlong) != 8) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_LongLengthWarning\"",
"\"The length requirement for the long type does not conform to the "
"type "
"definition.\"",
NULL);
++warning_count;
}
if (sizeof(aqfloat) != 4) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"",
"\"AqvmMemory_CheckMemoryConditions_FloatLengthWarning\"",
"\"The length requirement for the float type does not conform to the "
"type definition.\"",
NULL);
++warning_count;
}
if (sizeof(aqdouble) != 4) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"",
"\"AqvmMemory_CheckMemoryConditions_DoubleLengthWarning\"",
"\"The length requirement for the double type does not conform to the "
"type definition.\"",
NULL);
++warning_count;
}
if (sizeof(aqchar) != 1) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_CharLengthWarning\"",
"\"The length requirement for the char type does not conform to the "
"type "
"definition.\"",
NULL);
++warning_count;
}
if (sizeof(aqbool) != 1) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_BoolLengthWarning\"",
"The length requirement for the bool type does not conform to the type "
"definition.",
NULL);
++warning_count;
}
if (warning_count == 0) {
AqvmRuntimeDebugger_OutputReport("\"INFO\"",
"\"AqvmMemory_CheckMemoryConditions_CheckNormal\"",
"\"No memory conditions warning.\"", NULL);
}
return warning_count;
}
memory部分的代码位于/aqvm/memory。内含多个代码文件.
CMakeLists.txt
- 该目录下的CMake构建文件memory.h
- 内存的数据结构和相关函数memory.c
- 内存的相关函数的实现types.h
- 内存类型的定义该结构体存储有关内存的信息。 |type| 是一个指向数组的指针,该数组存储内存中每个字节的类型。每个字节使用4位来存储类型。因此,一个 uint8_t 变量可以存储2个类型。每个 uint8_t 变量的前4位用于偶数字节的类型,后4位用于奇数字节的类型。类型列表在 types.h 中。 |data| 是一个指向存储数据的内存的 void* 类型的指针。 |size| 是内存的大小。 注意:结构体 AqvmMemory_Memory 仅存储内存的信息。内存由存储字节码时的字节码函数分配。|memory| 和 |type| 的内存是字节码内存的一部分.
struct AqvmMemory_Memory {
uint8_t* type;
void* data;
size_t size;
};
检查系统中的内存条件。 返回警告数量.
int AqvmMemory_CheckMemoryConditions() {
int warning_count = 0;
if (sizeof(aqint) != 4) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_IntLengthWarning\"",
"\"The length requirement for the int type does not conform to the "
"type "
"definition.\"",
NULL);
++warning_count;
}
if (sizeof(aqlong) != 8) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_LongLengthWarning\"",
"\"The length requirement for the long type does not conform to the "
"type "
"definition.\"",
NULL);
++warning_count;
}
if (sizeof(aqfloat) != 4) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"",
"\"AqvmMemory_CheckMemoryConditions_FloatLengthWarning\"",
"\"The length requirement for the float type does not conform to the "
"type definition.\"",
NULL);
++warning_count;
}
if (sizeof(aqdouble) != 4) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"",
"\"AqvmMemory_CheckMemoryConditions_DoubleLengthWarning\"",
"\"The length requirement for the double type does not conform to the "
"type definition.\"",
NULL);
++warning_count;
}
if (sizeof(aqchar) != 1) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_CharLengthWarning\"",
"\"The length requirement for the char type does not conform to the "
"type "
"definition.\"",
NULL);
++warning_count;
}
if (sizeof(aqbool) != 1) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_BoolLengthWarning\"",
"The length requirement for the bool type does not conform to the type "
"definition.",
NULL);
++warning_count;
}
if (warning_count == 0) {
AqvmRuntimeDebugger_OutputReport("\"INFO\"",
"\"AqvmMemory_CheckMemoryConditions_CheckNormal\"",
"\"No memory conditions warning.\"", NULL);
}
return warning_count;
}
创建包含 |data|、|type| 和 |size| 的结构体 AqvmMemory_Memory。 该函数将分配一个 AqvmMemory_Memory 结构体,并将 |data|、|type| 和 |size| 复制到结构体中。返回指向该结构体的指针。如果创建失败则返回NULL.
struct AqvmMemory_Memory* AqvmMemory_CreateMemory(void* data, void* type,
size_t size) {
struct AqvmMemory_Memory* memory_ptr =
(struct AqvmMemory_Memory*)malloc(sizeof(struct AqvmMemory_Memory));
if (memory_ptr == NULL) {
AqvmRuntimeDebugger_OutputReport(
"\"ERROR\"", "\"AqvmMemory_CreateMemory_MemoryAllocationFailure\"",
"\"Failed to allocate memory.\"", NULL);
return NULL;
}
memory_ptr->data = data;
memory_ptr->type = type;
memory_ptr->size = size;
return memory_ptr;
}
释放 |memory_ptr| 的内存。无返回值。 注意:该函数仅释放结构体的内存。结构体中指向数据和类型的指针所指向的内存不会被释放。这些内存由字节码相关函数管理.
void AqvmMemory_FreeMemory(struct AqvmMemory_Memory* memory_ptr) {
free(memory_ptr);
}
设置 |memory| 中 |index| 字节处的数据类型为 |type|。|type| 应小于 4 位。 成功时返回 0。如果内存指针为 NULL,返回 -1。如果索引指针为 NULL,返回 -2。如果索引超出范围,返回 -3。如果类型超出范围,返回 -4.
int AqvmMemory_SetType(const struct AqvmMemory_Memory* memory, size_t index,
uint8_t type) {
if (memory == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_SetType_NullMemoryPointer\"",
"\"The memory pointer is NULL.\"", NULL);
return -1;
}
if (memory->type == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_SetType_NullTypePointer\"",
"\"The type pointer is NULL.\"", NULL);
return -2;
}
if (index > memory->size) {
AqvmRuntimeDebugger_OutputReport(
"\"ERROR\"", "\"AqvmMemory_SetType_OutOfMemoryRange\"",
"\"The index is out of memory range.\"", NULL);
return -3;
}
if (type > 0x0F) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_SetType_OutOfTypeRange\"",
"\"The type is out of range.\"", NULL);
return -4;
}
// Sets the type of the data at |index| bytes in memory.
// Since Aqvm stores type data occupying 4 bits and uint8_t occupying 8 bits,
// each uint8_t type location stores two type data. The storage locations
// (high 4 bits, low 4 bits) are set according to the parity of |index|. Even
// numbers are stored in the high bits of (|index| / 2) and odd numbers are
// stored in the low bits of (|index| / 2).
if (index % 2 != 0) {
memory->type[index / 2] = (memory->type[index / 2] & 0xF0) | type;
} else {
memory->type[index / 2] = (memory->type[index / 2] & 0x0F) | (type << 4);
}
return 0;
}
获取 |memory| 中 |index| 字节处的数据类型。 成功时返回小于 4 位 (0X0F) 的类型。如果内存指针为 NULL,返回 0x11。如果索引指针为 NULL,返回 0x12。如果索引超出内存范围,返回 0x13.
uint8_t AqvmMemory_GetType(struct AqvmMemory_Memory* memory, size_t index) {
if (memory == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_GetType_NullMemoryPointer\"",
"\"The memory pointer is NULL.\"", NULL);
return 0x11;
}
if (memory->type == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_GetType_NullTypePointer\"",
"\"The type pointer is NULL.\"", NULL);
return 0x12;
}
if (index > memory->size) {
AqvmRuntimeDebugger_OutputReport(
"\"ERROR\"", "\"AqvmMemory_GetType_OutOfMemoryRange\"",
"\"The index is out of memory range.\"", NULL);
return 0x13;
}
// Gets the type of the data at |index| bytes in memory.
// Since Aqvm stores type data occupying 4 bits and uint8_t occupying 8 bits,
// each uint8_t type location stores two type data. The storage locations
// (high 4 bits, low 4 bits) are set according to the parity of |index|. Even
// numbers are stored in the high bits of (|index| / 2) and odd numbers are
// stored in the low bits of (|index| / 2).
if (index % 2 != 0) {
return memory->type[index / 2] & 0x0F;
} else {
return (memory->type[index / 2] & 0xF0) >> 4;
}
}
将 |data_ptr| 指向的大小为 |size| 的数据写入 |memory| 中 |index| 字节处的数据。 成功时返回 0。如果内存指针为 NULL,返回 -1。如果索引指针为 NULL,返回 -2。如果索引超出内存范围,返回 -3。如果数据指针为 NULL,返回 -4.
int AqvmMemory_WriteData(struct AqvmMemory_Memory* memory, size_t index,
void* data_ptr, size_t size) {
if (memory == NULL) {
AqvmRuntimeDebugger_OutputReport(
"\"ERROR\"", "\"AqvmMemory_WriteData_NullMemoryPointer\"",
"\"The memory pointer is NULL.\"", NULL);
return -1;
}
if (memory->type == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_WriteData_NullTypePointer\"",
"\"The type pointer is NULL.\"", NULL);
return -2;
}
if (index > memory->size) {
AqvmRuntimeDebugger_OutputReport(
"\"ERROR\"", "\"AqvmMemory_WriteData_OutOfMemoryRange\"",
"\"The index is out of memory range.\"", NULL);
return -3;
}
if (data_ptr == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_WriteData_NullDataPointer\"",
"\"The data pointer is NULL.\"", NULL);
return -4;
}
// Since void* does not have a specific size, pointer moves need to be
// converted before moving.
memcpy((void*)((uintptr_t)memory->data + index), data_ptr, size);
return 0;
}
memory.h
完整代码:// Copyright 2024 AQ author, All Rights Reserved.
// This program is licensed under the AQ License. You can find the AQ license in
// the root directory.
#ifndef AQ_AQVM_MEMORY_MEMORY_H_
#define AQ_AQVM_MEMORY_MEMORY_H_
#include <stddef.h>
#include <stdint.h>
#include "aqvm/memory/types.h"
// The struct stores information about the memory.
// |type| is a pointer to an array that stores the type of each byte in the
// memory. Each byte uses 4 bits to store the type. So a uint8_t variable can
// store 2 types. Each uint8_t variable's first 4 bits are used for the even
// byte's type and the next 4 bits are used for the odd byte's type. The type
// list is in types.h.
// |data| is a pointer of type void* to the memory that stores the data.
// |size| is the size of the memory.
// NOTICE: The struct AqvmMemory_Memory only stores information of the memory.
// The memory is allocated by the bytecode function when storing the bytecode.
// The memory of |memory| and |type| is part of the bytecode memory.
struct AqvmMemory_Memory {
uint8_t* type;
void* data;
size_t size;
};
// Checks the memory conditions in the system.
// Returns the number of warnings.
int AqvmMemory_CheckMemoryConditions();
// Creates the struct AqvmMemory_Memory with |data|, |type|, and |size|.
// The function will allocate a struct AqvmMemory_Memory and copy |data|,
// |type|, and |size| into the struct. Returns a pointer to the struct if
// successful. Returns NULL if creation fails.
struct AqvmMemory_Memory* AqvmMemory_CreateMemory(void* data, void* type,
size_t size);
// Free the memory of the |memory_ptr|. No return.
// NOTICE: The function only free the memory of the struct. The memory pointed
// to by pointers to data and type in struct is not freed. This memory is
// managed by bytecode related functions.
void AqvmMemory_FreeMemory(struct AqvmMemory_Memory* memory_ptr);
// Sets the type of the data at |index| bytes in |memory| to |type|. |type|
// should be less than 4 bits.
// Returns 0 if successful. Returns -1 if the memory pointer is NULL. Returns -2
// if the type pointer is NULL. Returns -3 if the index is out of range. Returns
// -4 if the type is out of range.
int AqvmMemory_SetType(const struct AqvmMemory_Memory* memory, size_t index,
uint8_t type);
// Gets the type of the data at |index| bytes in |memory|.
// Returns the type that is less than 4 bits (0X0F) if successful. Returns 0x11
// if the memory pointer is NULL. Returns 0x12 if the type pointer is NULL.
// Returns 0x13 if the index is out of memory range.
uint8_t AqvmMemory_GetType(struct AqvmMemory_Memory* memory, size_t index);
// Writes the data that |data_ptr| points to of size |size| to the data of at
// |index| bytes in |memory|.
// Returns 0 if successful. Returns -1 if the memory pointer is NULL. Returns -2
// if the type pointer is NULL. Returns -3 if the index is out of range. Returns
// -4 if the data pointer is NULL.
int AqvmMemory_WriteData(struct AqvmMemory_Memory* memory, size_t index,
void* data_ptr, size_t size);
#endif
memory.c
完整代码:// Copyright 2024 AQ author, All Rights Reserved.
// This program is licensed under the AQ License. You can find the AQ license in
// the root directory.
#include "aqvm/memory/memory.h"
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "aqvm/memory/types.h"
#include "aqvm/runtime/debugger/debugger.h"
int AqvmMemory_CheckMemoryConditions() {
int warning_count = 0;
if (sizeof(aqint) != 4) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_IntLengthWarning\"",
"\"The length requirement for the int type does not conform to the "
"type "
"definition.\"",
NULL);
++warning_count;
}
if (sizeof(aqlong) != 8) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_LongLengthWarning\"",
"\"The length requirement for the long type does not conform to the "
"type "
"definition.\"",
NULL);
++warning_count;
}
if (sizeof(aqfloat) != 4) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"",
"\"AqvmMemory_CheckMemoryConditions_FloatLengthWarning\"",
"\"The length requirement for the float type does not conform to the "
"type definition.\"",
NULL);
++warning_count;
}
if (sizeof(aqdouble) != 4) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"",
"\"AqvmMemory_CheckMemoryConditions_DoubleLengthWarning\"",
"\"The length requirement for the double type does not conform to the "
"type definition.\"",
NULL);
++warning_count;
}
if (sizeof(aqchar) != 1) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_CharLengthWarning\"",
"\"The length requirement for the char type does not conform to the "
"type "
"definition.\"",
NULL);
++warning_count;
}
if (sizeof(aqbool) != 1) {
AqvmRuntimeDebugger_OutputReport(
"\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_BoolLengthWarning\"",
"The length requirement for the bool type does not conform to the type "
"definition.",
NULL);
++warning_count;
}
if (warning_count == 0) {
AqvmRuntimeDebugger_OutputReport("\"INFO\"",
"\"AqvmMemory_CheckMemoryConditions_CheckNormal\"",
"\"No memory conditions warning.\"", NULL);
}
return warning_count;
}
struct AqvmMemory_Memory* AqvmMemory_CreateMemory(void* data, void* type,
size_t size) {
struct AqvmMemory_Memory* memory_ptr =
(struct AqvmMemory_Memory*)malloc(sizeof(struct AqvmMemory_Memory));
if (memory_ptr == NULL) {
AqvmRuntimeDebugger_OutputReport(
"\"ERROR\"", "\"AqvmMemory_CreateMemory_MemoryAllocationFailure\"",
"\"Failed to allocate memory.\"", NULL);
return NULL;
}
memory_ptr->data = data;
memory_ptr->type = type;
memory_ptr->size = size;
return memory_ptr;
}
void AqvmMemory_FreeMemory(struct AqvmMemory_Memory* memory_ptr) {
free(memory_ptr);
}
int AqvmMemory_SetType(const struct AqvmMemory_Memory* memory, size_t index,
uint8_t type) {
if (memory == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_SetType_NullMemoryPointer\"",
"\"The memory pointer is NULL.\"", NULL);
return -1;
}
if (memory->type == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_SetType_NullTypePointer\"",
"\"The type pointer is NULL.\"", NULL);
return -2;
}
if (index > memory->size) {
AqvmRuntimeDebugger_OutputReport(
"\"ERROR\"", "\"AqvmMemory_SetType_OutOfMemoryRange\"",
"\"The index is out of memory range.\"", NULL);
return -3;
}
if (type > 0x0F) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_SetType_OutOfTypeRange\"",
"\"The type is out of range.\"", NULL);
return -4;
}
// Sets the type of the data at |index| bytes in memory.
// Since Aqvm stores type data occupying 4 bits and uint8_t occupying 8 bits,
// each uint8_t type location stores two type data. The storage locations
// (high 4 bits, low 4 bits) are set according to the parity of |index|. Even
// numbers are stored in the high bits of (|index| / 2) and odd numbers are
// stored in the low bits of (|index| / 2).
if (index % 2 != 0) {
memory->type[index / 2] = (memory->type[index / 2] & 0xF0) | type;
} else {
memory->type[index / 2] = (memory->type[index / 2] & 0x0F) | (type << 4);
}
return 0;
}
uint8_t AqvmMemory_GetType(struct AqvmMemory_Memory* memory, size_t index) {
if (memory == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_GetType_NullMemoryPointer\"",
"\"The memory pointer is NULL.\"", NULL);
return 0x11;
}
if (memory->type == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_GetType_NullTypePointer\"",
"\"The type pointer is NULL.\"", NULL);
return 0x12;
}
if (index > memory->size) {
AqvmRuntimeDebugger_OutputReport(
"\"ERROR\"", "\"AqvmMemory_GetType_OutOfMemoryRange\"",
"\"The index is out of memory range.\"", NULL);
return 0x13;
}
// Gets the type of the data at |index| bytes in memory.
// Since Aqvm stores type data occupying 4 bits and uint8_t occupying 8 bits,
// each uint8_t type location stores two type data. The storage locations
// (high 4 bits, low 4 bits) are set according to the parity of |index|. Even
// numbers are stored in the high bits of (|index| / 2) and odd numbers are
// stored in the low bits of (|index| / 2).
if (index % 2 != 0) {
return memory->type[index / 2] & 0x0F;
} else {
return (memory->type[index / 2] & 0xF0) >> 4;
}
}
int AqvmMemory_WriteData(struct AqvmMemory_Memory* memory, size_t index,
void* data_ptr, size_t size) {
if (memory == NULL) {
AqvmRuntimeDebugger_OutputReport(
"\"ERROR\"", "\"AqvmMemory_WriteData_NullMemoryPointer\"",
"\"The memory pointer is NULL.\"", NULL);
return -1;
}
if (memory->type == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_WriteData_NullTypePointer\"",
"\"The type pointer is NULL.\"", NULL);
return -2;
}
if (index > memory->size) {
AqvmRuntimeDebugger_OutputReport(
"\"ERROR\"", "\"AqvmMemory_WriteData_OutOfMemoryRange\"",
"\"The index is out of memory range.\"", NULL);
return -3;
}
if (data_ptr == NULL) {
AqvmRuntimeDebugger_OutputReport("\"ERROR\"",
"\"AqvmMemory_WriteData_NullDataPointer\"",
"\"The data pointer is NULL.\"", NULL);
return -4;
}
// Since void* does not have a specific size, pointer moves need to be
// converted before moving.
memcpy((void*)((uintptr_t)memory->data + index), data_ptr, size);
return 0;
}
通过这些代码的配合,共同构成了完整的Aqvm的内存架构,有效缓解内存压力的同时,提高了Aqvm的运行效率.
我们正在更加努力地开发AQ虚拟机。如果您想了解更多信息或参与开发工作,请关注我们的官网:https://www.axa6.com 和 Github:https://github.com/aq-org/AQ.
本文章基于AQ License:https://github.com/aq-org/AQ/blob/main/LICENSE 发布,如有需要,请根据AQ License进行改编或转载.
最后此篇关于一种优秀的虚拟机内存架构-AQ的文章就讲到这里了,如果你想了解更多关于一种优秀的虚拟机内存架构-AQ的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我有一个使用 Oracle 高级队列的 JMS op top 的应用程序。我想对显示消息内容的队列表进行查询(在我的情况下是 XML)。因此,当我执行“从 [queue_table] 中选择 user
使用较新版本的 Oracle DB (12.2.0.1),我们开始收到 ORA-00932,因为代码可以很好地与旧的 DB 服务器配合使用。此外,驱动程序报告异常的奇怪细节: ORA-00932: i
源链接:https://www.axa6.com/zh/an-excellent-virtual-machine-memory-architecture 简介 虚拟机内存架构直接影响虚拟机的性能和
我们正在升级我们的基础设施,为此我们正在从 Oracle 10g 迁移到 11g。 我们使用 Oracle GoldenGate 进行数据复制,据我们所知,它不支持 AQ 消息的复制。 对于持久队列,
我在oracle中创建了一个AQ,并用Java编写了2个JMS消费者来监听队列。我有时观察到,如果我在队列中生成一些消息;队列中出队消息的数量大于入队数量。这意味着某些消息会被消费两次。 我创建了具有
我有多个运行的docker(版本18.09.0,构建4d60db4)容器,我希望立即停止它们。 This blog post准确地显示了如何实现此目标,太好了! 我可以使用docker ps -aq列
聊聊JUC包下的底层支撑类-AbstractQueuedSynchronizer(AQS) juc包下的一堆并发工具类是我们日常开发特别是面试中常被拿来问的八股文之一,为了工作也好,为了面试也
这个问题在这里已经有了答案: Docker unknown shorthand flag: 'a' in -aq) (2 个回答) 1年前关闭。 我按照教程 https://phoenixnap.co
我根本不使用高级队列,但 AQ$_PLSQL_NTFNnnnn 调度程序作业的数量不断增长。 目前有 8 个此类职位。正因为如此,我需要刷新最大同时运行作业数。 大约 2 个月前,限制为 10 个还可
我们有一个 Oracle AQ 队列引发事件。 我们有 Java Oracle AQ 客户端处理这些事件。 出于灾难恢复的目的,我们有另一个始终关闭的客户端。但我们也遇到过灾难恢复练习让第二个客户端处
Oracle 10g 中的触发器为常规表中的行子集生成更新插入和删除消息。这些消息由两个字段组成: 唯一的行 ID。 非唯一 ID。 当使用这些消息时,我想对遵守以下约束的双端队列进程施加一个顺序:
我正在使用带有高级队列 (AQ) 和 Java JMS API 的 Oracle 数据库 [11.2]。我当前的 oracle 设置是默认设置,没有额外的调整参数。高层架构: 数据库将消息排入持久队列
1、面试官:如何设计一个秒杀系统?请你阐述流程? 这一面试题答案参考自三太子敖丙的文章:阿里面试官问我:如何设计秒杀系统?我给出接近满分的回答 秒杀系统要解决的几个问题? ① 高并发
我们有一个基于 Oracle AQ 的消息传递系统 - 它运行良好,入队和出队没有任何问题。 现在我们收到了在启动前和运行时添加一些完整性检查的请求,例如“检查所提供的 db-user 的队列是否确实
AQ$_MESSAGES_EXCEPTION首先我知道有这个问题:How to clear a queue in Oracle AQ但它没有答案。 我在 Oracle AQ 的异常队列中有很多消息 (
过去几天我一直在互联网上搜索用于消息入队/双端队列的 Oracle Advanced Queue 的任何正在运行的示例实现,但没有取得任何成功。 我试图遵循 oracle 文档中提到的规范,但我对此不
AQ$_MESSAGES_EXCEPTION首先我知道有这个问题:How to clear a queue in Oracle AQ但它没有答案。 我在 Oracle AQ 的异常队列中有很多消息 (
我是第一次测试 Oracle AQ。我已成功在我创建的队列中创建了 2000 行测试插入。 现在,我想清除这些内容。当我自学时,我将到期时间设置为一个月。我等不了那么久。而且我认为我不应该将它们从队列
我已经设置了单个客户 Oracle AQ。我在 Java Web 应用程序中使用 CLIENT_ACKNOWLEDGE 模式观察来自此队列的消息。但是,一旦我在 onMessage 方法中收到消息,这
我正在编写一个工作流系统,该系统的每一步都完全由明确的人机交互驱动。也就是说,一项任务被分配给一个人,该人从几个有限的选项中进行选择{批准、拒绝、转发},然后将其发送给下一个人或终止。 只是好奇 Or
我是一名优秀的程序员,十分优秀!