Julia对象在内存中的位置
对象结构('jl_value_t`)
`Jl_value_t’结构是属于Julia垃圾回收器的内存块的名称,并表示与内存中的Julia对象关联的数据。 在没有类型信息的情况下,它只是一个不透明的指针。
typedef struct jl_value_t* jl_pvalue_t;
每个’jl_value_t’结构都包含在’jl_typetag_t’结构中,该结构包含有关Julia对象的元数据,例如其类型和垃圾收集器的可访问性。
typedef struct {
opaque metadata;
jl_value_t value;
} jl_typetag_t;
任何Julia对象的类型都是最终对象’jl_datatype_t’的实例。 要请求它,您可以使用`jl_typeof()`函数。
jl_value_t *jl_typeof(jl_value_t *v);
对象的结构取决于其类型。 可以使用反射方法来检查它。 您可以通过调用get-field方法之一来访问该字段。
jl_value_t *jl_get_nth_field_checked(jl_value_t *v, size_t i);
jl_value_t *jl_get_field(jl_value_t *o, char *fld);
如果先验地知道所有字段类型都是指针,则值也可以作为数组访问直接检索。
jl_value_t *v = value->fieldptr[n];
例如,打包指针’uint16_t’存储如下。
struct {
opaque metadata;
struct {
uint16_t data; // -- 2 bytes
} jl_value_t;
};
此对象使用’jl_box_uint16()'创建。 请注意,`jl_value_t’指针指的是一段数据,而不是结构顶部的元数据。
在许多情况下,值可能被解包存储(只有数据,没有元数据,或者甚至不存储,而是简单地存储在寄存器中),因此假设容器地址是唯一标识符是不安全的。 要比较两个未知对象的等价性,请使用egal(identity)检验(对应于Julia中的`===`函数)。
int jl_egal(jl_value_t *a, jl_value_t *b);
这种优化应该对API相对透明,因为只要需要`jl_value_t`指针,对象就会按需打包。
请注意,只有当对象是可变的时,才允许修改内存中的’jl_value_t`指针。 否则,更改值可能会扰乱程序,结果将是不确定的。 可以请求值的可变性属性,如下所示。
int jl_is_mutable(jl_value_t *v);
如果正在保存的对象是`jl_value_t’指针,则还必须通知Julia垃圾回收器。
void jl_gc_wb(jl_value_t *parent, jl_value_t *ptr);
手册部分 Julia代码实现是现阶段必读的,因为它涵盖了各种类型的其他打包和解包细节,以及理解垃圾回收内的交互。
某些嵌入式类型的镜像结构https://github.com/JuliaLang/julia/blob/master/src/julia.h [在’朱莉娅定义。h']。 相应的全局对象’jl_datatype_t’是使用以下方法创建的https://github.com/JuliaLang/julia/blob/master/src/jltypes.c [`jl_init_types`in’jltypes.c']。
垃圾收集器标签的位
垃圾回收器使用来自`jl_typetag_t`结构的元数据部分的几个位来跟踪系统中的每个对象。 有关此算法的更多信息可以在实现注释中找到。 https://github.com/JuliaLang/julia/blob/master/src/gc.c [垃圾收集器在`gc。c']。
选择对象
大多数新对象都是使用’jl_new_structv()'分配的。
jl_value_t *jl_new_struct(jl_datatype_t *type, ...);
jl_value_t *jl_new_structv(jl_datatype_t *type, jl_value_t **args, uint32_t na);
无论如何,对象 'isbits'也可以直接从内存构建。
jl_value_t *jl_new_bits(jl_value_t *bt, void *data)
并且有些对象具有特殊的构造函数,必须使用这些构造函数来代替上述函数。
类别:
jl_datatype_t *jl_apply_type(jl_datatype_t *tc, jl_tuple_t *params);
jl_datatype_t *jl_apply_array_type(jl_datatype_t *type, size_t dim);
虽然这些是最常用的变体,但也有较低级别的构造函数可以在https://github.com/JuliaLang/julia/blob/master/src/julia.h ['朱莉娅。h']。 它们在`jl_init_types()`中用于创建引导Julia系统映像所需的初始类型。
元组:
jl_tuple_t *jl_tuple(size_t n, ...);
jl_tuple_t *jl_tuplev(size_t n, jl_value_t **v);
jl_tuple_t *jl_alloc_tuple(size_t n);
元组的表示在Julia对象表示生态系统中是唯一的。 在某些情况下,对象 '基地。tuple()`可以是指向元组中包含的对象的指针数组,相当于以下内容。
typedef struct {
size_t length;
jl_value_t *data[length];
} jl_tuple_t;
但是,在其他情况下,元组可以转换为匿名类型。 `isbits'和存储解包或根本不存储(如果它在一般上下文中没有作为`jl_value_t*`使用)。
符号:
jl_sym_t *jl_symbol(const char *str);
函数和方法安装:
jl_function_t *jl_new_generic_function(jl_sym_t *name);
jl_method_instance_t *jl_new_method_instance(jl_value_t *ast, jl_tuple_t *sparams);
数组:
jl_array_t *jl_new_array(jl_value_t *atype, jl_tuple_t *dims);
jl_array_t *jl_alloc_array_1d(jl_value_t *atype, size_t nr);
jl_array_t *jl_alloc_array_nd(jl_value_t *atype, size_t *dims, size_t ndims);
请注意,其中许多具有用于各种特殊目的的替代突出显示功能。 这里给出的列表显示了最常见的用例。 更完整的列表可以通过检查找到https://github.com/JuliaLang/julia/blob/master/src/julia.h [头文件’julia。h']。
在Julia中,存储通常使用`newstruct()(或特殊类型的`newobj()
)分配。
jl_value_t *newstruct(jl_value_t *type);
jl_value_t *newobj(jl_value_t *type, size_t nfields);
在最低级别,通过调用垃圾回收器(在`gc中)来分配内存。c`),然后用类型标记。
jl_value_t *jl_gc_allocobj(size_t nbytes);
void jl_set_typeof(jl_value_t *v, jl_datatype_t *type);
!!! 注意"过时警告" 有关使用`jl_gc_allocobj`函数的文档和信息可能已过时。
请注意,所有对象都以4字节的倍数分配,并且与平台指针的大小一致。 内存是从池中为小对象分配的,或者直接使用`malloc()`函数为大对象分配的。
单例类型
单个类型只有一个实例,没有数据字段。 单个实例的大小为0字节,仅由其元数据组成。 例如,'nothing::Nothing'。 |
请参阅[Single Types](../manual/types.md#man-singleton-types)和[Empty or missing values](../manual/faq.md#Nothingness-and-missing-values)部分。