简体   繁体   English

CArray的Destructor大约需要30秒才能运行

[英]Destructor for CArray takes about 30 seconds to run

I'm curious if someone could explain to me why when I call a destructor on the following array: 我很好奇是否有人可以向我解释为什么在以下数组上调用析构函数时:

CArray<READ_ENTRY> arr;

It takes about 30 seconds to finish? 完成大约需要30秒?

The arr array at the time has about 240,000 entries, which I thought wasn't that many. 当时的arr数组大约有240,000个条目,我认为不是很多。 Also to compare memory usage, I took the working set from the Task Manager for my process before that array is filled in and after, and the working set grew by about 322 MB. 另外,为了比较内存使用情况,我在填充阵列前后都从任务管理器中获取了进程的工作集,并且该工作集增加了约322 MB。

Also if there's something that I can do to optimize/speed it up? 另外,如果有什么我可以做的优化/加快?

EDIT: 编辑:

The data that is being stored in this array is distributed as such: 存储在此数组中的数据按以下方式分布:

  • CString members contain relatively short strings that are between 10 to 300 wchar s long. CString成员包含相对较短的字符串,其长度在10到300 wchar之间。

  • My MEM_ARRAY byte arrays also contain relatively small amounts of data: 我的MEM_ARRAY字节数组还包含相对少量的数据:

    • procPrivs is about 20-100 bytes on average. procPrivs平均约为20-100字节。

    • userSID is even smaller, it's the size of the user's SID (no more than 50 bytes.) userSID甚至更小,它是用户SID的大小(不超过50个字节)。

  • The rest are just 4 or 8 byte members. 其余的只是4或8个字节的成员。

EDIT2: In Release build it takes exactly the same amount of time to run. EDIT2:在Release版本中,它花费的时间完全相同。

The following structures are defined as such: 这样定义了以下结构:

struct READ_ENTRY{
    DWORD flags;
    FILETIME ftLogTimeUTC;
    short wTimeDiffMin;

    int nOSErrorCode;
    int nSpecCode;

    DWORD dwMessageID;
    DWORD dwMessageCtr;
    DWORD dwMessageAllowBackSecs;

    BYTE wProductType;
    DWORD dwOSType;
    DWORD dwMajorVersion;
    DWORD dwMinorVersion;
    DWORD dwBuildNumber;
    WORD wServicePackMajor;
    WORD wServicePackMinor;
    WORD wSuiteMask;
    WORD wProcessorArchitecture;
    ULONGLONG dwActiveProcessorMask;

    DWORD dwProcID;
    DWORD dwThreadID;
    LCID lcidThread;

    MEM_ARRAY procPrivs;

    CString strUserName;
    MEM_ARRAY userSID;

    CString strModName;

    CString strMsgTitle;
    CString strMsgDesc;

    READ_ENTRY()
    {
        flags = DBXF_NONE;
        ftLogTimeUTC.dwLowDateTime = 0;
        ftLogTimeUTC.dwHighDateTime = 0;
        wTimeDiffMin = 0;

        nOSErrorCode = 0;
        nSpecCode = 0;

        dwMessageID = 0;
        dwMessageCtr = 0;
        dwMessageAllowBackSecs = 0;

        wProductType = 0;
        dwOSType = 0;
        dwMajorVersion = 0;
        dwMinorVersion = 0;
        dwBuildNumber = 0;
        wServicePackMajor = 0;
        wServicePackMinor = 0;
        wSuiteMask = 0;
        wProcessorArchitecture = 0;
        dwActiveProcessorMask = 0;

        dwProcID = 0;
        dwThreadID = 0;
        lcidThread = NULL;
    }
};

and: 和:

struct MEM_ARRAY{
    BYTE* pMem;
    int ncbSzMem;

    MEM_ARRAY() :
        pMem(NULL)
        , ncbSzMem(0)
    {
    }
    ~MEM_ARRAY()
    {
        freeMem();
    }
    MEM_ARRAY(BYTE* pSrcSID, int ncbSz) :
        pMem(NULL)
        , ncbSzMem(0)
    {
        copyMem(pSrcSID, ncbSz);
    }
    MEM_ARRAY(const MEM_ARRAY& s) :
        pMem(NULL)
        , ncbSzMem(0)
    {
        copyMem(s.pMem, s.ncbSzMem);
    }
    MEM_ARRAY& operator = (const MEM_ARRAY& s)
    {
        copyMem(s.pMem, s.ncbSzMem);
        return *this;
    }

    void freeMem()
    {
        if(pMem)
        {
            delete[] pMem;
            pMem = NULL;
        }

        ncbSzMem = 0;
    }

    void copyMem(BYTE* pSrcSID, int ncbSz)
    {
        if(pSrcSID != pMem)
        {
            freeMem();

            pMem = new (std::nothrow) BYTE[ncbSz];
            ASSERT(pMem);
            if(pMem)
            {
                memcpy(pMem, pSrcSID, ncbSz);
                ncbSzMem = ncbSz;
            }
        }
        else
            ASSERT(ncbSz == ncbSzMem);
    }
};

EDIT3: Here's a sample of how to fill in the array: EDIT3:以下是如何填充数组的示例:

#define SIZEOF(f) (sizeof(f) / sizeof(f[0]))

{
CArray<READ_ENTRY> arr;

BYTE dummy[256];
srand((UINT)time(NULL));
for(int i = 0; i < sizeof(dummy); i++)
    dummy[i] = (BYTE)rand();

READ_ENTRY re;

arr.SetSize(240000);    //Optimize it, since we know the final size

for(int t = 0; t < 240000; t++)
{
    static LPCTSTR words[] = {
        L"success",  L"added",  L"new", L"entry",
        L"didn't",  L"counter", L"as",  L"ran",
        L"out",  L"this",   L"first",   L"because",
        L"the",  L"just",   L"error",   L"if",
        L"or",  L"manually",    L"simple",  L"program",
        L"how",  L"what",   L"title",   L"great",
    };


    CString strTitle;
    int nCntW = GetRandomNumber(0, 12);
    for(int i = 0; i < nCntW; i++)
    {
        if(!strTitle.IsEmpty())
            strTitle += L" ";

        strTitle += words[GetRandomNumber(0, SIZEOF(words))];
    }

    CString strDesc;
    int nCntWDesc = GetRandomNumber(0, 100);
    for(int i = 0; i < nCntWDesc; i++)
    {
        if(!strDesc.IsEmpty())
            strDesc += L" ";

        strDesc += words[GetRandomNumber(0, SIZEOF(words))];
    }

    re.strMsgTitle = strTitle;  //Use some randomness for these members
    re.strMsgDesc = strDesc;

    re.strModName = L"Test Module v.1.0.0.0";
    re.strUserName = L"mycomputername\\my user name";

    re.procPrivs.copyMem(dummy, GetRandomNumber(10, 100));
    re.userSID.copyMem(dummy, GetRandomNumber(10, 50));

    arr.SetAtGrow(t, re);
}

//Destructor will be called here
}


ULONG GetRandomNumber(ULONG nNumMin, ULONG nNumMax)
{
    ULONG nMin, nMax;
    if(nNumMin <= nNumMax)
    {
        nMin = nNumMin;
        nMax = nNumMax;
    }
    else
    {
        nMin = nNumMax;
        nMax = nNumMin;
    }

    ULONG nRnd = ((ULONG)(rand() & 0x7fff) << 17) | 
        ((ULONG)(rand() & 0x7fff) << 2) |
        ((ULONG)(rand() & 0x3));

    return nMax > nMin ? (nRnd % (nMax - nMin)) + nMin : nMin;
}

Is the problem happening in release build too? 问题也发生在发布版本中吗? (I cant comment it seems noobs dont get enough reputation to comment). (我无法发表评论,看来菜鸟们没有获得足够的声誉来发表评论)。 what platform? 什么平台?

If the slow down is there in release build as well and you are seeing CPU spikes on delete then you might want to fix your data structures, at the risk of stating the obvious you'r heap is being stressed out. 如果发行版构建中也出现了放慢的情况,并且删除时看到CPU峰值,那么您可能要修复数据结构,冒着明显地使您的堆受压的风险。 Freeing large amount of memory is a highly CPU intensive task. 释放大量内存是一项占用大量CPU的任务。

You can ... Try clubbing the memory blocks into a larger block. 您可以...尝试将内存块合并为一个更大的块。 Use fixed length strings, it will cause external fragmentation but you can decide where to draw the line. 使用固定长度的字符串,这会导致外部碎片,但是您可以决定在哪里画线。

One approach is to have the Carray per CPU and a separate heap for each one of them. 一种方法是让每个CPU有Carray,并且每个CPU有一个单独的堆。 This will make allocation and deallocation more concurrent. 这将使分配和释放更加并发。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM