C/Pascal的堆管理器,自动填充零字节的释放内存

Max*_*tin 4 heap free memory-management heap-memory shared-memory

您如何看待用零字节填充已释放(未实际使用)的页面的选项?这可以提高Windows下的性能,也可以提高VMWare和其他虚拟机环境下的性能?例如,VMWare和HyperV计算内存页面的哈希值,如果内容相同,则将此页面标记为虚拟机内部和同一主机上的虚拟机之间的"共享",直到页面被修改.它有效地减少了内存消耗.Windows也是如此 - 它以不同的方式处理零页面,将它们视为免费.

当我们调用FreeMem/ReallocMem时,我们可以让堆管理器自动用零填充内存.作为替代选项,我们可以有一个函数按需求将空内存归零,即仅在显式调用此函数时.当然,这个功能必须是线程安全的.用零填充内存的缺点是触及可能已经变为虚拟内存的内存,从而发出页面错误.除此之外,任何内存存储操作都很慢,因此我们的程序将会更慢,尽管程度未知(可能可以忽略不计).

如果我们设法用零完全填充4-K页面,则管理程序或Windows将明确将其标记为零页面.但即使是部分归零也可能是有益的,因为管理程序可以使用LZ或类似算法压缩页面以节省物理内存.

我只是想知道你的意见是否由堆管理器本身填充空的堆内存和零字节的好处将超过这种技术的缺点.

当我们购买减少的物理内存消耗时,归零是否物有所值?

Mit*_*tch 7

如果您有一个页面,其内容您不再关心但仍希望保留它,则可以调用VirtualAlloc(和变体)并传递该MEM_RESET标志.

来自VirtualAllocMSDN:

MEM_RESET

表示由lpAddress和dwSize指定的内存范围中的数据不再受关注.不应从页面文件中读取或写入页面.但是,内存块将在以后再次使用,因此不应该将其解除.此值不能与任何其他值一起使用.

使用此值并不能保证使用MEM_RESET操作的范围将包含零.如果您希望范围包含零,请退出内存然后重新发送.

这样可以实现两全其美 - 您没有将内存归零的成本,并且系统没有将其重新分配的成本.您可以利用已经调整好的内存管理器零池.

在Linux下MADV_FREE(或者MADV_DONTNEED对于Posix)标志也存在类似的功能madvise. Glibc在其堆的实现中使用此函数.:

/* 
 * Stack:
 * int shrink_heap (heap_info *h, long diff)
 * int heap_trim (heap_info *heap, size_t pad) at arena.c:660
 * void _int_free (mstate av, mchunkptr p, int have_lock) at malloc.c:4097
 * void __libc_free (void *mem) at malloc.c:2948
 * void free(void *mem)
 */

static int
shrink_heap (heap_info *h, long diff)
{
  long new_size;

  new_size = (long) h->size - diff;
  /* ... snip ...  */

  __madvise ((char *) h + new_size, diff, MADV_DONTNEED);

  /* ... snip ...  */
  h->size = new_size;
  return 0;
}
Run Code Online (Sandbox Code Playgroud)


sta*_*ole 5

如果您的堆在用户空间中,这将永远不会工作.内核只能信任自己,而不能信任用户空间.如果内核将页面归零,则可将其视为零.如果用户空间说它将页面归零,那么内核仍然需要检查它.它可能也是零.用户空间可以做的一件事就是丢弃页面.这标志着他们"不在乎".然后内核可以将它们视为零.但是手动将用户空间中的页面归零是徒劳的.