std::list什么情况下会出现error的错误?

red-fly 2016-03-07 07:27:16
为了对内存的管理,使用了std模板,定义了两个变量:

map<int, mem_s_info> m_mapMemBusyList; // 正在使用的内存列表,key为内存地址
list<mem_s_info> m_vecMemFreeList;

m_mapMemBusyList用来保存正在使用的内存,m_vecMemFreeList保存未被使用的内存。
其中结构mem_s_info定义如下(这个结构本身可以不用去关心它):

struct mem_s_info
{
char *pszBuf; // 内存地址
int len; // 内存长度
int id; // 内存的标示号,暂时没什么用处
__time64_t ttCreate; // 创建时间
__time64_t ttAccess; // 最后一次访问时间,即被重新利用的时间

#ifdef _DEBUG
mem_ins_info memIns; // 用于保存分配该内存的代码信息
#endif
};

流程如下:
在要分配一个内存时,首先从m_vecMemFreeList中查找是否有对应长度的空闲内存,如果有,就把它从m_vecMemFreeList中移到m_mapMemBusyList中,如果没有,则分配一个新的,然后加入到m_mapMemBusyList中。代码如下:

char *CMemoryManagerS::CreateMem( const int len, const char* file /*= NULL*/, const char *function /*= NULL*/, const int line /*= 0*/ )
{
if ( len < 0 || len > 0x4000000 )
return NULL;

// 如果为0,则也分配8个字节
int startlen = len;
if ( len == 0 )
startlen = 1;

mem_s_info *pstuSInfo;
char *pReturnPtr = NULL;
list<mem_s_info>::iterator iterFree;
CAutoCri criFree( m_csMemBusy);
for ( iterFree = m_vecMemFreeList.begin(); iterFree != m_vecMemFreeList.end(); iterFree++ )
{
pstuSInfo = &(*iterFree);
if ( pstuSInfo->len <= startlen )
continue;

if ( pstuSInfo->len > startlen * 5/4 && pstuSInfo->len >= 32 )
{
// 比需求内存大的最小内存,比需求内存大了1/4,所以为了节约,重新进行申请,防止过分地浪费内存。
break;
}

// 搞定
pstuSInfo->ttAccess = _time64(NULL);
memset( pstuSInfo->pszBuf, 0, pstuSInfo->len );

// 把此条记录移到使用列表中
pReturnPtr = pstuSInfo->pszBuf;
#ifdef _DEBUG
SetMemIns( pstuSInfo, file, function, line );
#endif
m_mapMemBusyList[(int)pReturnPtr] = *pstuSInfo;
m_vecMemFreeList.erase( iterFree );
return pReturnPtr;
}
criFree.Release();

// 需要分配新的内存。弄成8字节对齐,估计运行的效率会高一些
int irelen = startlen + 8; // 不是+7,目的是要使分配出来的内存一定比实际指定的要大,最多大8个字节,最少大1个字节
irelen /= 8;
irelen *= 8;

mem_s_info stuSInfo;
stuSInfo.pszBuf = new char[irelen];
stuSInfo.len = irelen;

CAutoCri criCounter( m_csIDCounter );
stuSInfo.id = m_memIDCounter++;
criCounter.Release();

stuSInfo.ttCreate = _time64(NULL);
stuSInfo.ttAccess = stuSInfo.ttCreate;
if ( stuSInfo.pszBuf == NULL )
{
return NULL; // 分配失败
}

memset( stuSInfo.pszBuf, 0, stuSInfo.len );
#ifdef _DEBUG
SetMemIns( &stuSInfo, file, function, line );
#endif
CAutoCri criBusy2( m_csMemBusy );
m_mapMemBusyList[(int)stuSInfo.pszBuf] = stuSInfo;
criBusy2.Release();

return stuSInfo.pszBuf;
}


在删除时,直接把要删除的从m_mapMemBusyList中移到m_vecMemFreeList中即可,代码如下:

UINT32 CMemoryManagerS::DeleteMem( const char *pmemAddress )
{
map<int, mem_s_info>::iterator iter;
list<mem_s_info>::iterator iterFree;
mem_s_info memInfo = {0};

CAutoCri criBusy( m_csMemBusy);
iter = m_mapMemBusyList.find( (int)pmemAddress );
if ( iter == m_mapMemBusyList.end() )
{
return errorcode_MEM_DELETEALREADY;
}

// 把它从使用表中移到未使用的列表中,并修改访问时间
memInfo = iter->second;
memInfo.ttAccess = _time64(NULL);
m_mapMemBusyList.erase( iter );
cntBusy = m_mapMemBusyList.size();

// 注意,必需先使用,然后再删除。注意必需按照从小到大的顺序插入进去

iterFree = m_vecMemFreeList.begin();
while ( iterFree != m_vecMemFreeList.end() )
{
if ( iterFree->len < memInfo.len )
{
iterFree++;
continue;
}
break;
}
m_vecMemFreeList.insert( iterFree, memInfo );

criBusy.Release();
ShinkList(); // 这一行用于删除m_vecMemFreeList中停留时间过长的那些内存,在出问题时此代码未生效,所以本贴说的问题和此函数无关
return errorcode_SUCCESS;
}


环境:vs2010,所以在变量窗口中可以看到ma和list的各项状态,正常情况如下:

m_vecMemFreeList [0] 结构mem_s_info的各字段值
[1] 结构mem_s_info的各字段值
[2] 结构mem_s_info的各字段值
[3] 结构mem_s_info的各字段值
... ...


失败时如下的形式:

m_vecMemFreeList [0] 结构mem_s_info的各字段值
[1] 结构mem_s_info的各字段值
[2] 结构mem_s_info的各字段值
[error]
[error]
[error]
... ...

注意,实际的数量有很多,即那些error都是在m_vecMemFreeList的有效个数以内。
初步认为很可能是内存越界导致的,但还不确定
大伙帮忙看下是什么问题导致的,如何定位这种问题
...全文
210 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
redui 2016-03-08
  • 打赏
  • 举报
回复
用vector保存指针,指针根据实际情况分配内存,如果需要按照从小到大排序,直接用stl的sort函数即可。 其实不管用那种方式,有两个原则:一是内存集中在一个地方管理(分配和释放);二是一个数据只分配一次内存,不要出现分配多次和数据复制的情况发生,其它使用和搜索请使用指针
gz_qmc 2016-03-08
  • 打赏
  • 举报
回复
在用对的情况不会
red-fly 2016-03-08
  • 打赏
  • 举报
回复
引用 3 楼 oyljerry 的回复:
是不是对list等有多线程访问操作等,是否有加锁保护
是多线程访问,有加锁: CAutoCri criFree( m_csMemBusy);
oyljerry 2016-03-08
  • 打赏
  • 举报
回复
是不是对list等有多线程访问操作等,是否有加锁保护
red-fly 2016-03-08
  • 打赏
  • 举报
回复
问题解决,经过多次测试没有发现这个问题了。 这个内存管理的类本身没有问题,是另外的代码有一个内存长度变量没有初始化,但用它分配的内存似乎有问题,好像越界了,导致不确定性的内存覆盖,结果总是表现在上面贴出来的内存管理类上。 当然这个内存管理的类,可以再根据实际情况进行改进,使效率提升
red-fly 2016-03-07
  • 打赏
  • 举报
回复
引用 1 楼 redui 的回复:
你这样内存复制来复制去的太乱太麻烦,应该专门使用一个数组来存放结构体,然后用map和list保存指针,用来指示已用的和空闲的,其实只要保存已用的就够了,不在容器里面的指针说明是空闲的。或者不用指针,用数组的索引标识是否已用
数组的个数不固定,而且变化范围比较大,另外就是每个项所对应的内存长度也不固定,范围很广,从几十字节到几MB字节。如果采用数组,那可能会经常有删除、添加等操作,相当不方便。 不在容器中说明是空闲的,那确实,所以这里有两个容器,一个是map,装“忙”的内存,这样在删除时可以直接找到,另外一个是list装从小到大排列的空闲项
redui 2016-03-07
  • 打赏
  • 举报
回复
你这样内存复制来复制去的太乱太麻烦,应该专门使用一个数组来存放结构体,然后用map和list保存指针,用来指示已用的和空闲的,其实只要保存已用的就够了,不在容器里面的指针说明是空闲的。或者不用指针,用数组的索引标识是否已用

16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧