我正在编写一个带有2阶段输入过程的32位.NET程序:
它通过C ++ / CLI使用本机C ++将不定数量的文件解析为相应的SQLite数据库(都具有相同的模式)。 C ++“new”的分配通常会消耗最多1GB的虚拟地址空间(2GB可用;我知道3GB扩展但这只会延迟问题)。
它使用复杂的SQL查询(从C#运行)将数据库合并到一个数据库中。我为合并的数据库设置了cache_size为1GB,以便合并部分具有最小的页面错误。
我的问题是第2阶段的缓存不会重新使用由'new'分配的1GB内存,并且在第1阶段由'delete'正确释放。我知道没有泄漏,因为在离开第1阶段后,'私有字节'下降到一个低的量,就像我期望的那样。然而,“虚拟大小”仍然是C ++使用的最高峰。
C ++和SQLite缓存之间的这种非共享导致我的虚拟地址空间不足。我怎样才能解决这个问题,最好以符合标准的方式解决?我真的想将C ++分配的内存释放回操作系统。
答案 0 :(得分:4)
这不是你可以从C ++抽象级别有效控制的东西(换句话说,你无法确定你的程序发布到C ++运行时的内存是否会被释放到操作系统)。使用特殊分配策略和非标准扩展来尝试处理问题可能无法正常工作,因为您无法控制您使用的外部库如何处理内存(例如,如果有缓存数据)。
一种可能的解决方案是将C ++部分移动到外部进程,一旦创建了SQLite数据库,它就会终止。有一个外部过程会引入一些烦恼(例如,对发生的事情保持“实时”控制有点困难),但也开辟了更多的可能性,如并行处理,即使库不支持多线程或通过网络使用多台机器。
答案 1 :(得分:2)
由于您正在与C ++ / CLI进行互操作,因此您可能使用Microsoft的编译器。
如果是这种情况,那么您可能想要查找_heapmin
。退出“阶段1”后,调用它,如果从操作系统分配的完整块现在是空闲的,它将释放C ++堆管理器保存的内存块回到操作系统。
答案 2 :(得分:0)
在Linux上,我们使用了google malloc(http://code.google.com/p/google-perftools/)。它具有向操作系统释放空闲内存的功能:MallocExtension::instance()->ReleaseFreeMemory()
。
理论上,gcmalloc适用于Windows,但我从未在那里亲自使用过它。
答案 3 :(得分:0)
您可以从C#中将其从GC中分配出来,固定它,使用它,然后允许它返回,从而释放它并让GC压缩它并重新使用内存。