我很好奇是否有人可以向我解释为什么当我在下面的数组上调用析构函数时:
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:在发布版本中,运行时间完全相同。
以下结构定义如下:
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;
}
答案 0 :(得分:1)
问题是否也在发布版本中发生? (我不能评论它似乎新闻没有得到足够的声誉评论)。什么平台?
如果发布版本中的速度减慢,并且您在删除时看到CPU峰值,那么您可能希望修复数据结构,冒着明显表明您的堆压力过大的风险。释放大量内存是一项高度CPU密集型任务。
你可以......尝试将内存块分成更大的块。使用固定长度的字符串,它会导致外部碎片,但您可以决定在哪里绘制线条。
一种方法是每个CPU都有Carray,每个CPU都有一个单独的堆。这将使分配和释放更加并发。