大家在使用Chrome浏览器的时候,只要在地址栏输入 about:memory,便可以详细的查
看浏览器中各种元素的内存使用情况,现在我们就来研究并实现这个功能。

在 Chrome的代码中,我们可以看到一个叫memory_watcher的工具,这个便是关键所在
了。
memory_watcher中定义了MemoryWatcher的类,初始化代码如下:
MemoryWatcher::MemoryWatcher()
: file_(NULL),
hooked_(false),
active_thread_id_(0) {
MemoryHook::Initialize();
CallStack::Initialize();
block_map_ = new CallStackMap();
// Register last - only after we're ready for notifications!
Hook();
}
从代码中我们可以清楚的发现,监视内存使用使用的是 Hook 技术,我们接着再来看看
MemoryHook是如何实现的。
在 MemoryHook::Hook中,我们看到他Hook了几乎所有的内存分配函数:
bool MemoryHook::Hook() {
DCHECK(!hooked_);
if (!hooked_) {
DCHECK(global_hook_);
// Luckily, Patch() doesn't call malloc or windows alloc routines
// itself -- though it does call new (we can use PatchWithStub to
// get around that, and will need to if we need to patch new).
HMODULE hkernel32 = ::GetModuleHandle(L"kernel32");
CHECK(hkernel32 != NULL);
HMODULE hntdll = ::GetModuleHandle(L"ntdll");
CHECK(hntdll != NULL);
// Now that we've found all the functions, patch them
INSTALL_PATCH(HeapCreate);
INSTALL_PATCH(HeapDestroy);
INSTALL_PATCH(HeapAlloc);
INSTALL_PATCH(HeapReAlloc);
INSTALL_PATCH(HeapFree);
INSTALL_PATCH(VirtualAllocEx);
INSTALL_PATCH(VirtualFreeEx);
INSTALL_PATCH(MapViewOfFileEx);
INSTALL_PATCH(MapViewOfFile);
INSTALL_PATCH(UnmapViewOfFile);
INSTALL_NTDLLPATCH(NtUnmapViewOfSection);
INSTALL_PATCH(GlobalAlloc);
INSTALL_PATCH(GlobalReAlloc);
INSTALL_PATCH(GlobalFree);
INSTALL_PATCH(LocalAlloc);
INSTALL_PATCH(LocalReAlloc);
INSTALL_PATCH(LocalFree);
// We are finally completely hooked.
hooked_ = true;
}
return true;
}
为了简化代码,这些操作都是使用宏来完成的。
有趣的,为了使操作变得简单,Chrome 将分配内存的可修改大小的标志都去掉了,在
像使用 LocalReAlloc 的时候重新分配内存,并将原来的数据拷贝回去,这样就大大的减轻
了内存分配管理的不确定因素。
static HLOCAL WINAPI Perftools_LocalAlloc(UINT uFlags, SIZE_T dwBytes) {
// LocalAlloc is built atop HeapAlloc anyway. So we don't track these.
// LocalAlloc will internally call into HeapAlloc and we track there.
// Force all memory to be fixed.
uFlags &= ~LMEM_MOVEABLE;
HLOCAL rv = patch_LocalAlloc()(uFlags, dwBytes);
return rv;
}
static HLOCAL WINAPI Perftools_LocalReAlloc(HLOCAL hMem, SIZE_T dwBytes,
UINT uFlags) {
// LocalDiscard is a macro which calls LocalReAlloc with size 0.
if (dwBytes == 0) {
return patch_LocalReAlloc()(hMem, dwBytes, uFlags);
}
HGLOBAL rv = Perftools_LocalAlloc(uFlags, dwBytes);
if (hMem != 0) {
size_t size = LocalSize(hMem);
if (size > dwBytes)
size = dwBytes;
// Note: size could be 0; HeapAlloc does allocate 0 length buffers.
memcpy(rv, hMem, size);
Perftools_LocalFree(hMem);
}
return rv; |