2010-10-12 17 views
4

如果我有一个本地C++程序并查看它的初始“专用字节”内存计数器,为什么在创建对象并删除对象后它不会回到它的原始值?为什么进程的“Private Bytes”内存计数器永远不会回到它的原始值?

例如,如果我有一个应用程序(32位,本机C + + MFC),有两个按钮。 一个在循环中分配一个对象的1,000,000个实例,然后另一个按钮则删除那些相同的对象。

如果我看看我的专用字节计数器的过程,我有以下3个值:

说明..........专用字节数
============= =================== ===
App Started ................. 1,608K
Objects。创建........ 33,176K
对象。删除.......... 2,520K

泄漏912K(2520-1608)?

假设我的代码没有泄漏内存,我相信这不是为什么专用字节数不会回到EXACT初始值?

如果我再上两个按钮点击(没有重新启动的程序)(第一按钮创建另一个百万对象)和第二删除它们我有这样的:

对象。创建........ 33,472K
对象。删除.......... 2,552K

新的泄漏(2552年至2520年)= 32K

我只是寻找关于为什么内存也不会回到原单值的解释。

示例代码(剥离出来,以降低噪声产生的一些代码):

class Person 
{ 
public: 
    Person(void); 
    ~Person(void); 

    Person* Next; 
    int A; 
    int B; 
    int C; 
    int D; 

}; 


class Cdelme_MFC2005_MemoryTestDlg : public CDialog 
{ 
// some code stripped out here to simplify reading. 

    Person* m_PeopleList_First; 
    Person* m_PeopleList_Last; 

public: 
    afx_msg void OnBnClickedButtonAllocate(); 
    afx_msg void OnBnClickedButtonFree(); 
}; 


Cdelme_MFC2005_MemoryTestDlg::Cdelme_MFC2005_MemoryTestDlg(CWnd* pParent /*=NULL*/) 
    : CDialog(Cdelme_MFC2005_MemoryTestDlg::IDD, pParent) 
{ 
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); 

    m_PeopleList_First = NULL; 
    m_PeopleList_Last = NULL; 

} 


void Cdelme_MFC2005_MemoryTestDlg::OnBnClickedButtonAllocate() 
{ 
    if (m_PeopleList_First == NULL) 
    { 
     m_PeopleList_First = new Person(); 
     m_PeopleList_First->A = 0; 
     m_PeopleList_Last = m_PeopleList_First; 
    } 

    int MAX = 1000000; 
    for (int i = 0; i <MAX ; i++) 
    { 
     Person* p = new Person(); 
     p->A = i; 
     m_PeopleList_Last->Next = p; 
     m_PeopleList_Last = p; 
    } 
} 

void Cdelme_MFC2005_MemoryTestDlg::OnBnClickedButtonFree() 
{ 
    Person* p = m_PeopleList_First; 
    while (p != NULL) 
    { 
     Person* pNext = p->Next; 
     delete p; 
     p = pNext; 
    } 
    m_PeopleList_First = NULL; 
    m_PeopleList_Last = NULL; 
} 
+0

'Person'构造函数将'Next'设置为'NULL'吗?如果不是,链表中的最后一项将指向垃圾。我不认为这会导致你的内存泄漏。 – Nate 2010-10-12 16:01:06

+0

是的,它的确如此。对不起,关于这个ommision – kevin 2010-10-12 16:05:40

回答

1

这不是一个内存泄漏的指示。操作系统只计算分配给您的进程的4k大小的页面。您的进程中运行的堆分配器将代表您请求并释放OS页面。堆管理器在释放它之后可能会保留内存,以便稍后重新用于其他对象。

您需要检测应用程序以查找内存泄漏,和/或运行长时间运行的压力测试来检测累积泄漏。

+0

感谢您的意见。我认为你对堆管理员保留内存以供重用的答案听起来很可能。我将尝试与Jerry的答案一起进行测试。 – kevin 2010-10-12 16:12:29

2

这里有几个问题。首先,当你的存储器为delete时,标准库通常会做而不是释放内存回操作系统。它通常保留该内存的所有权,但将其标记为可用于其他分配。由于您明显使用MS VC++,因此您在执行delete之后可以使用_heapwalk来查看仍在进程堆中的空闲块。如果你真的想要,你也可以调用_heapmin来释放(至少大部分)空闲内存回操作系统。回头的时候(MS VC++ 4.0,如果内存服务的话)MS有一个直接使用操作系统内存管理的标准库的版本,但是性能很糟糕(很好地说明),所以这不会太长。其次,MFC在后台分配各种“东西”来使事情发挥作用,但在事后不立即释放它们(因为它大部分是或多或少看不见的,不存在简单/直接的方式让你释放它)。

+0

再次感谢您的意见。你已经给了我几个有用的项目来跟进我的调查(_heapwalk和_heapMin)。我将修改我的程序并查看_heapmin的影响。 关于你对MFC的第二个评论我想我可以将我的简单程序改为一个简单的Win32控制台应用程序来删除MFC以减少此等式中的变量数量。 谢谢。 – kevin 2010-10-12 16:14:30

+0

@kevin:我不会删除MFC只是喷气式飞机。 MFC库有可选的内置内存泄漏跟踪。您在应用程序退出时会收到您未能删除的所有对象的日志。非常便利。 http://msdn.microsoft.com/en-us/library/c99kz476(VS.80).aspx – 2010-10-12 17:14:51

+0

@jdv:的确如此。尽管它不是很有名,但是你可以在没有MFC的情况下获得相当类似的东西(http://msdn.microsoft.com/en-us/library/x98tx3cf(VS.80).aspx)。 – 2010-10-12 17:35:18

相关问题