程序性能优化之 内存分配影响
2017-04-28 14:37
183 查看
本篇不是介绍内存相关知识,如内存分配,布局等, 只是在程序优化性能时,结合案例跟大家分享,期间遇到情况,将知识点,做梳理,便于后续归类和记录,技术水平有限,如果有什么问题,及时给予指正。
案例一: 程序某模块操作之后, 响应很慢,需要排查和优化性能。
先说明一下排查过程,因为功能比较复杂,所以一般有什么捷径吗?除非这个代码是自己写,否则还针对没有什么捷径,只能通过日志,然后在各个可能点上打日志,然后根据日志分析消耗主要点,然后对其进行分析。
性能优化难点在于找到主要消耗点, 只能通过时间和经验的累计,由量到质的变化。言归正传,说明具体问题, 排查之后,主要在一个循环中耗时,类似代码如下:
CString strInfor;
clock_t sTime, eTime;
sTime = clock();
int nSize = m_vecData.Size();
for(int nInd=0; nInd<nSize ; ++nInd)
{
strInfor = strInfor + _T("&"), + m_vecData.at(nInd);
}
eTime= clock();
double dbGap = (eTime - sTime) /CLOCKS_PER_SEC;
以上代码片段,也没有其他逻辑, 简单一个字符拼接,在size=10000时,会消耗将近2秒左右时间,如果size=50000时居然耗时24描述, 以上数据为debug模式下测试
针对如上问题排查: strInfor = strInfor + _T("&"), + m_vecData.at(nInd); 这个行代码,弄清到底做了写什么东东,导致这么旧:
排查之后,上述代码主要做了如下几件事情:两次+操作,一次=操作, 跟踪代码之后,;
一次+操作经历如下步骤:
1, 先计算+之后大小,然后申请内存;
2, 底层两次memmove操作将值拷贝的新的内存中;
一次=操作会经历如下:
1,+新生成的值复制给予受托人Infor;
2, 针对之前的做一次Free释放操作;
具体的代码,大家可以单步调试中去跟踪, 经过分析,频繁的内存申请,释放比较耗时耗力,必然消耗性能,看来一定要正视每一个接口背后的实现逻辑,否则有可能怎么影响性能都不晓得。
根据以上的排查和cstring的接口,选如下实现替代:
CString strInfor;
clock_t sTime, eTime;
sTime = clock();
int nSize = m_vecData.Size();
for(int nInd=0; nInd<nSize ; ++nInd)
{
strInfor.Append(_T("&"));
strInfor.Append(m_vecData.at(nInd));
}
eTime= clock();
先测试性能:同样的条件10000是,计划不耗时,职位0毫秒(140-140),50000万时,几乎耗时为0描述, (165-124);
可见对性能的影响,根据调试发现其主要过程如下:
1,一次根据大小策略,分配内存操作;
2,一次memmove操作将值拷贝的新的内存中;
其主要性能差异主要在接口中,针对分配算法的策略情况,具体代码如下:
PXSTR PerpareWrite(int nLenght)
{
CStringData* pOldData = GetData();
int nShared = 1- pOldData->nRefs;
int nTooShort = pOldData->nAllocLenght -nLenght;
if(nShared |nTooShort )
{
PerpareWrite2(nLenght);
}
}
////////////////////核心算法
void PerpareWrite(int nLenght)
{
CStringData* pOldData = GetData();
if(pOldData ->nDataLenght>nLenght)
{
nLenght = pOldData ->nDataLenght;
}
if(pOldData->IsShared())
{
Fork(nLenght ); ///里面只是根据大家申请内存,没做任何策略
}
else if(pOldData ->nAllocLenght <nLenght))
{
//////////// 如下策略,是否大家在那里见过, vector是动态数据,其中针对内存做预留处理,避免多次申请
int nNewLenght = pOldData ->nAllocLenght ;
if(nNewLenght >1024)
{
nNewLenght += 1024;
}
else
{
nNewLenght *=2;
}
if(nNewLenght <nLenght)
{
nNewLenght = nLenght;
}
Reallocate(nNewLenght );
}
}
通过以上分析, 大家应该明白问题所在,以及解决, 仅此是程序性能提升不小,尤其针对大量数据,也可以为后续自己的内存申请提供策略。如果有什么不足或者错误,欢迎大家及时给予指正!
案例一: 程序某模块操作之后, 响应很慢,需要排查和优化性能。
先说明一下排查过程,因为功能比较复杂,所以一般有什么捷径吗?除非这个代码是自己写,否则还针对没有什么捷径,只能通过日志,然后在各个可能点上打日志,然后根据日志分析消耗主要点,然后对其进行分析。
性能优化难点在于找到主要消耗点, 只能通过时间和经验的累计,由量到质的变化。言归正传,说明具体问题, 排查之后,主要在一个循环中耗时,类似代码如下:
CString strInfor;
clock_t sTime, eTime;
sTime = clock();
int nSize = m_vecData.Size();
for(int nInd=0; nInd<nSize ; ++nInd)
{
strInfor = strInfor + _T("&"), + m_vecData.at(nInd);
}
eTime= clock();
double dbGap = (eTime - sTime) /CLOCKS_PER_SEC;
以上代码片段,也没有其他逻辑, 简单一个字符拼接,在size=10000时,会消耗将近2秒左右时间,如果size=50000时居然耗时24描述, 以上数据为debug模式下测试
针对如上问题排查: strInfor = strInfor + _T("&"), + m_vecData.at(nInd); 这个行代码,弄清到底做了写什么东东,导致这么旧:
排查之后,上述代码主要做了如下几件事情:两次+操作,一次=操作, 跟踪代码之后,;
一次+操作经历如下步骤:
1, 先计算+之后大小,然后申请内存;
2, 底层两次memmove操作将值拷贝的新的内存中;
一次=操作会经历如下:
1,+新生成的值复制给予受托人Infor;
2, 针对之前的做一次Free释放操作;
具体的代码,大家可以单步调试中去跟踪, 经过分析,频繁的内存申请,释放比较耗时耗力,必然消耗性能,看来一定要正视每一个接口背后的实现逻辑,否则有可能怎么影响性能都不晓得。
根据以上的排查和cstring的接口,选如下实现替代:
CString strInfor;
clock_t sTime, eTime;
sTime = clock();
int nSize = m_vecData.Size();
for(int nInd=0; nInd<nSize ; ++nInd)
{
strInfor.Append(_T("&"));
strInfor.Append(m_vecData.at(nInd));
}
eTime= clock();
先测试性能:同样的条件10000是,计划不耗时,职位0毫秒(140-140),50000万时,几乎耗时为0描述, (165-124);
可见对性能的影响,根据调试发现其主要过程如下:
1,一次根据大小策略,分配内存操作;
2,一次memmove操作将值拷贝的新的内存中;
其主要性能差异主要在接口中,针对分配算法的策略情况,具体代码如下:
PXSTR PerpareWrite(int nLenght)
{
CStringData* pOldData = GetData();
int nShared = 1- pOldData->nRefs;
int nTooShort = pOldData->nAllocLenght -nLenght;
if(nShared |nTooShort )
{
PerpareWrite2(nLenght);
}
}
////////////////////核心算法
void PerpareWrite(int nLenght)
{
CStringData* pOldData = GetData();
if(pOldData ->nDataLenght>nLenght)
{
nLenght = pOldData ->nDataLenght;
}
if(pOldData->IsShared())
{
Fork(nLenght ); ///里面只是根据大家申请内存,没做任何策略
}
else if(pOldData ->nAllocLenght <nLenght))
{
//////////// 如下策略,是否大家在那里见过, vector是动态数据,其中针对内存做预留处理,避免多次申请
int nNewLenght = pOldData ->nAllocLenght ;
if(nNewLenght >1024)
{
nNewLenght += 1024;
}
else
{
nNewLenght *=2;
}
if(nNewLenght <nLenght)
{
nNewLenght = nLenght;
}
Reallocate(nNewLenght );
}
}
通过以上分析, 大家应该明白问题所在,以及解决, 仅此是程序性能提升不小,尤其针对大量数据,也可以为后续自己的内存申请提供策略。如果有什么不足或者错误,欢迎大家及时给予指正!
相关文章推荐
- [C++应用程序性能优化]内存分配失败处理
- xen环境下的内存与CPU分配:性能优化
- 程序性能优化之map影响
- [C++应用程序性能优化]程序使用内存区
- 程序性能优化提升方法--大页内存
- Xen环境下的内存与CPU分配:性能优化
- 关于VS编译的程序内存分配只能用1.5~2G上限的优化方案
- 关于VS编译的程序内存分配只能用1.5~2G上限的优化方案
- (转)!!频繁分配释放内存导致的性能问题的分析 --(附)malloc分配原理浅析 mmap关注焦点 如何优化分配内存
- C# ASP.NET 优化程序性能、降低内存使用、提高程序运行速度
- ORACLE 10G中SGA,PGA内存分配对系统性能的影响
- 针对动态内存分配、释放的性能优化checklist
- Android性能优化第(四)篇---Allaction Tracing追踪内存分配的轨迹
- c++14对内存分配性能的重大优化
- 频繁分配释放内存导致的性能问题的分析 --(附)malloc分配原理浅析 mmap关注焦点 如何优化分配内存
- 使用tcmmaloc优化mysql的内存分配性能
- 性能优化:影响程序启动性能的因素
- Android进阶#(6/12)让程序更优的技术——性能优化_内存泄漏
- Hibernate程序性能优化的考虑要点
- 使用内存映射文件来提高你程序的性能