前面提到了持久化内存编程的启程资料:
https://blog.csdn.net/SweeNeil/article/details/90293313
在持久化内存开发工具中,提供了各种各样的库,这些在pmem的github介绍以及pmem.io中都有提到,下面就直接把github上面的直接拿出来:
上面描述了各个库的说明,在其中,看到libpmemobj提供的功能还算全面,所以就使用libpmemobj来进行持久化内存的开发。
下面就翻译一篇资料里的内容来实际操作一下持久化内存。
在操作持久化内存之前,如果我们没有持久化内存,那么就需要在内存DRAM中模拟持久化内存Persistent Memory,模拟持久化内存的方式可以参考:https://blog.csdn.net/SweeNeil/article/details/90265226
下面文章翻译自:http://pmem.io/2015/06/13/accessing-pmem.html
在正是开始之前,读者也可以先阅读一些介绍:
http://pmem.io/2014/09/01/nvm-library-overview.html
http://pmem.io/2015/06/12/pmem-model.html
内存池
我们可以阅读overview,从中了解到操作系统以内存映射文件的方式使用持久性内存,我们将其(文件)称为池。
pmemobj库提供了一个易于管理这些池的界面,因此开发者无需手动创建文件或对其进行mmap。
创建池使用pmemobj_create API函数完成的,该函数采用了创建文件的函数和布局所需的常用参数,布局是开发者设定的用于标识池的字符串。
创建完成后,要使用就需要用pmemobj_open API,传递给pmemobj_open的布局必须与创建池的布局相匹配。
与任何其他OS资源一样,当不再需要持久性内存池时,通常在应用程序结束时,必须使用pmemobj_close释放池。为了验证池的完整性,在libpmemobj也提供了pmemobj_check函数来验证所有必需的元数据是否一致。
持久性指针
现在我们已经映射了内存区域,如何访问它?
我们可以考虑一下常规指针,将它归结为一种非常基础的方式,指针是虚拟地址空间的开始到它所指向的事物的开头之间的字节数。
现在将指针转换到持久性内存,在一个应用程序中可以打开多个池,持久性指针的大小是常规指针的两倍,并包含从池的开头(而不是VAS)和池的唯一ID的偏移量。
结构本身看起来像这样:
typedef struct pmemoid {
uint64_t pool_uuid_lo;
uint64_t off;
} PMEMoid;
如果知道了池映射到的虚拟地址,则可以执行简单的添加以获取直接指针,如下所示:
(void *)((uint64_t)pool + oid.off)
这正是pmemobj_direct的作用,它采用PMEMoid(持久性指针)并将其转换为可以解除引用的常规指针。
池ID用于确定池当前映射的位置(因为每次启动应用程序时,内存映射区域的实际地址可能不同)。
所有打开的池都存储在具有2个散列函数的cuckoo散列表(cuckoo hash table)中,因此这意味着当调用pmemobj_direct时,最多会发生两次查表就可以找到池地址。
root对象
考虑以下场景:
- 分配一块持久化内存(假设一个类似malloc的接口)
- 在持久化内存中写一个字符串
- 关闭应用程序
这时候如何找到包含刚才创建的字符串的指针?
想要的数据将在池中的某个位置,但除了扫描整个文件以找到匹配的字符之外,无法真正找到它。
例如,可以在池中选择一个随机偏移量并将其视为已知地址。但这是