簡體   English   中英

CArray的Destructor大約需要30秒才能運行

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

我很好奇是否有人可以向我解釋為什么在以下數組上調用析構函數時:

CArray<READ_ENTRY> arr;

完成大約需要30秒?

當時的arr數組大約有240,000個條目,我認為不是很多。 另外,為了比較內存使用情況,我在填充陣列前后都從任務管理器中獲取了進程的工作集,並且該工作集增加了約322 MB。

另外,如果有什么我可以做的優化/加快?

編輯:

存儲在此數組中的數據按以下方式分布:

  • CString成員包含相對較短的字符串,其長度在10到300 wchar之間。

  • 我的MEM_ARRAY字節數組還包含相對少量的數據:

    • procPrivs平均約為20-100字節。

    • userSID甚至更小,它是用戶SID的大小(不超過50個字節)。

  • 其余的只是4或8個字節的成員。

EDIT2:在Release版本中,它花費的時間完全相同。

這樣定義了以下結構:

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;
    }
};

和:

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:以下是如何填充數組的示例:

#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;
}

問題也發生在發布版本中嗎? (我無法發表評論,看來菜鳥們沒有獲得足夠的聲譽來發表評論)。 什么平台?

如果發行版構建中也出現了放慢的情況,並且刪除時看到CPU峰值,那么您可能要修復數據結構,冒着明顯地使您的堆受壓的風險。 釋放大量內存是一項占用大量CPU的任務。

您可以...嘗試將內存塊合並為一個更大的塊。 使用固定長度的字符串,這會導致外部碎片,但是您可以決定在哪里畫線。

一種方法是讓每個CPU有Carray,並且每個CPU有一個單獨的堆。 這將使分配和釋放更加並發。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM