如何缓存1000个大型C++对象

how to cache 1000s of large C++ objects

本文关键字:1000个 大型 C++ 对象 缓存 何缓存      更新时间:2023-10-16

环境:Windows 8 64位、Windows 2008服务器64位Visual Studio(专业版)2012 64位

列表L//我在程序中缓存了1000个大型CMyObject,这些对象由我的windows服务程序中的不同线程共享。

对于我们的SaaS中间件产品,我们在内存中缓存1000个大型C++对象(只读常量对象,每个对象的大小约为4MB),这会耗尽系统的内存。我们可以将磁盘文件(或其他由操作系统管理的持久机制)与C++对象相关联吗?不需要共享/进程间通信。

如果磁盘文件在整个过程(我们的windows服务程序)中都能工作,那么它就足够了。只读常量C++对象由同一windows服务中的不同线程共享。

我甚至考虑使用对象数据库(如mongoDB)来存储对象,然后在每次使用时加载/卸载这些对象。虽然比读取序列化文件快(希望如此),但它仍然会破坏性能。

其目的是出于性能原因保留C++对象的缓存,并避免每次都必须加载/卸载序列化的C++对象。如果这个磁盘文件是操作系统管理的,并且需要对我们的代码进行最小的调整,那就太好了。

提前感谢您的回复。

操作系统以您描述的方式管理的唯一东西就是交换文件。您可以创建一个单独的应用程序(将其称为"缓存助手"),它将所有对象加载到内存中并等待请求。由于操作系统不使用内存页面,因此操作系统最终会将页面转移到交换文件中,只有在需要时才会调用该文件。可以通过命名的管道或插座与应用程序进行通信。

这种方法的缺点是,这种缓存的性能将高度不稳定,并且可能降低整个服务器的性能。

我建议您编写自己的缓存算法/应用程序,因为您稍后可能需要调整其属性。

一个解决方案当然是简单地加载每个对象,并让操作系统根据需要处理从磁盘交换到磁盘的问题。(或者动态加载,但除非对象完全被破坏,否则永远不要丢弃)。如果存在比其他对象更频繁使用的对象数量,则这种方法将很好地工作。从swapspace加载几乎可以肯定比你能写的任何东西都快。例外情况是,如果您事先知道哪些对象下一步更有可能或不太可能被使用,并且可以在内存不足的情况下"抛出"正确的对象。

当然,你也可以使用内存映射文件——这将允许你像读取内存一样读取和写入文件(当内存可用时,操作系统会将内容缓存在RAM中)。在WIndows上,您将使用CreateFileMappingOpenFileMapping创建/打开文件映射,然后使用MapViewOfFile将文件映射到内存中。完成后,使用UnmapViewOfFile"取消映射"内存,然后使用CloseHandle关闭FileMapping。

关于文件映射,唯一担心的是它下次可能不会出现在内存中的同一地址,所以你不能在文件映射中有指针,下次加载与二进制相同的数据。当然,每次都创建一个新的文件映射会很好。

因此,您的数千个大型对象都有构造函数、析构函数、虚拟函数和指针。这意味着你不能轻易地将它们分页出来。不过,操作系统可以帮你做到这一点,所以你最实用的方法就是添加更多的物理内存,可能是SSD交换卷,并使用64位地址空间。(我不知道在你的操作系统上有多少是可寻址的,但大概足以容纳你的~4G个对象)。

你的第二个选择是找到一种方法来节省一些内存。这可能是使用专门的分配器来减少空闲,或者删除间接层。你没有提供足够的关于你的数据的信息,我无法对此提出具体建议。

第三种选择,假设您可以将程序放入内存中,则只是加快反序列化的速度。你能把格式改成更有效解析的格式吗?你能按需快速反序列化对象吗?

最后一个选项,也是大多数工作,是手动管理交换文件。作为第一步,将大量多态类拆分为两个是明智的:多态轻量级(每个具体子类型有一个实例)和扁平聚合上下文结构。此聚合是您可以安全地交换地址空间的部分。

现在,您只需要一个内存映射的分页机制,某种缓存跟踪当前映射的页面,可能是一个智能指针用页面+偏移量取代原始指针,可以按需映射数据,等等。同样,您还没有提供足够的数据结构和访问模式信息来提出更详细的建议。