1

环境:Windows 8 64位,Windows 2008 server 64位 Visual Studio(专业版)2012 64位

清单 L;//我的程序中有 1000 个大的 CMyObject 进行缓存,由我的 Windows 服务程序中的不同线程共享。

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

如果磁盘文件在整个过程(我们的 Windows 服务程序)期间工作,它就足够了。只读 const C++ 对象由同一 Windows 服务中的不同线程共享。

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

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

提前感谢您的回复。

4

3 回答 3

0

所以你成千上万的海量对象都有构造函数、析构函数、虚函数和指针。这意味着您不能轻松地将它们分页。不过,操作系统可以为您完成,因此您最实用的方法就是添加更多物理内存,可能是 SSD 交换卷,并使用该 64 位地址空间。(我不知道在您的操作系统上实际可寻址多少,但大概足以容纳您〜 4G 的对象)。

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

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

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

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

于 2013-07-24T07:44:07.503 回答
0

唯一以您描述的方式管理的操作系统是交换文件。您可以创建一个单独的应用程序(让它称为“缓存助手”),它将所有对象加载到内存中并等待请求。由于它不使用它的内存页面,操作系统最终会将页面替换为交换文件,仅在需要时/在需要时调用它。与应用程序的通信可以通过命名管道或套接字来完成。

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

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

于 2013-07-23T10:51:13.857 回答
0

一种解决方案当然是简单地加载每个对象,并让操作系统根据需要处理将其从磁盘换入/换出到磁盘。(或动态加载,但永远不要丢弃,除非对象被绝对销毁)。如果有许多对象比其他对象更频繁使用,这种方法将很有效。而且从交换空间加载几乎肯定比你能写的任何东西都要快。例外情况是,如果您事先知道接下来更可能或不太可能使用哪些对象,并且可以在内存不足的情况下“丢弃”正确的对象。

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

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

于 2013-07-23T11:34:42.517 回答