Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1812876
  • 博文数量: 473
  • 博客积分: 13997
  • 博客等级: 上将
  • 技术积分: 5953
  • 用 户 组: 普通用户
  • 注册时间: 2010-01-22 11:52
文章分类

全部博文(473)

文章存档

2014年(8)

2013年(38)

2012年(95)

2011年(181)

2010年(151)

分类: LINUX

2012-02-02 15:28:49

http://www.opensubscriber.com/message/mythtv-dev@mythtv.org/562057.html

似乎是mysql导致的。不应该是自己程序的问题,我觉得自己的设计应该是合理的,不会存在这类问题。但我已经忘记了自己使用的mysql版本。

 

http://blog.csdn.net/tommy_lgj/archive/2008/08/18/2790452.aspx

似乎没多大用。我基本上可以拿人头担保,绝对没有重复释放,因为我每次释放内存,都会将指针置空;而释放前,会首先判断指针是否非空。

 

现在又出现新错误:program received signal sigabrt aborted

应该是前面出了问题。那怎么找出前面的问题呢?——  一处一处慢慢地注释吧。

 

找到原因了!这个问题从8月份开始出现,一直到现在才解决。

可能原因是频繁操作堆栈,导致栈结构损坏。

如下:

void Func()

{
        LOGGER_BUFFER log_buffer;

        
        m_log_buffer_list.push_back(log_buffer);

}

 LOGGER_BUFFER为4KB的大小。如果注释掉push_back语句,就一切正常。而push_back的操作事实上就是new一个LOGGER_BUFFER,再将log_buffer的内容复制过去。

于是改为:

void Func()

{
        LOGGER_BUFFER * plog_buffer=new LOGGER_BUFFER ;

        ATLASSERT(plog_buffer!=NULL);

        if(plog_buffer==NULL)
        {
            return ;
        }

        LOGGER_BUFFER & log_buffer=*plog_buffer ;


        m_log_buffer_list.push_back(log_buffer);
        delete plog_buffer;

}

 ATLASSERT是我自定义的,linux是没有这个的。

至此ok。没想到问题居然出在这儿,这个今年最得意的杰作之一。


引用如下:

看了博主的smallbin double linked list corrupted一文。“可能原因是频繁操作堆栈,导致栈结构损坏”这句话值得商榷,操作的频度是不可能导致栈损坏的。

个 人认为,报错的原因:在第一段代码中,LOGGER_BUFFER log_buffer; 这句在栈里用了4K空间创建结构体,那么因为m_log_buffer_list.push_back(log_buffer)的参数是值传递,调用 push_back的话又要消耗4K的栈空间,结果很可能发生overflow。
修改后的代码虽然没错,但是性能仍然偏低(调用push_back要在栈里分配、复制4K的数据)。可以把m_log_buffer_list.push_back的参数类型改为结构体指针类型试试,这样通过指针直接使用堆里的现有数据就行了。


我当初没法给出更好的解释,而自己的这个解释也说不通。只是从没想过值传递会导致这个问题,命中十环的一句话,让我恍然大悟。另外,效率方面,我是不想自己动态释放内存,所以使用栈。而m_log_buffer_list是stl库的,会自动分配堆内存,并拷贝LOGGER_BUFFE栈内存的数据,在删除节点的时候,m_log_buffer_list自己就释放了内存,我就刚好省事儿了,可以少写一些代码,哈哈。——效率方面,正如命中十环所说的,确实比较低的。


2011.04.09 下午

再仔细看了一下,不是值传递的缘故。我使用的是stl的list库。我看了一下list库的push_back的源码(VC 2010版本),是引用传递。引用传递的话,就不应该存在撑爆堆栈的问题了(只是传递了四个字节)。引用传递和指针传递差不多。
难道是gcc的C++标准库——tl的list库,它的push_back函数参数是值传递?也不大可能。


那么,到底是什么原因呢?我觉得只能这样解释了。

这段代码的栈内存分配,是很少的,一个指针,一个引用类型的变量。也就是说,临时变量占用了8个字节的栈内存。

void Func()

{
        LOGGER_BUFFER * plog_buffer=new LOGGER_BUFFER ;

        ATLASSERT(plog_buffer!=NULL);

        if(plog_buffer==NULL)
        {
            return ;
        }

        LOGGER_BUFFER & log_buffer=*plog_buffer ;


        m_log_buffer_list.push_back(log_buffer);
        delete plog_buffer;

}

再看之前的。

void Func()

{
        LOGGER_BUFFER log_buffer;

        
        m_log_buffer_list.push_back(log_buffer);

}

LOGGER_BUFFER占用了4KB的内存。


所以,改动前后,栈内存的使用从4KB减少到8字节。但是,为什么一个函数只能使用4KB的栈内存呢?而且只是使用了4KB,程序就出现了栈溢出!(系统是Ubuntu)

那只能解释为堆栈耗用过多。类似的情况就是,即使函数没有任何临时变量(栈内存),但是如果函数嵌套调用几万次,堆栈还是会溢出!因为,栈内存不仅仅存放了临时变量,还存放了函数地址等信息。

同样地,这里的情况则很可能是,Func本身确确实实只有4KB,但是调用Func的上一层或者几层函数使用了过多的堆栈,导致堆栈资源紧张。


分析:

关于这段代码的内存分配。

void Func()

{
        LOGGER_BUFFER log_buffer;

        
        m_log_buffer_list.push_back(log_buffer);

}


首先是log_buffer的栈内存4KB,然后是调用push_back函数压栈的代码。然后push_back内部new动态开辟一块缓冲区(堆内存),从引用传递的参数log_buffer复制数据,并保持这块缓冲区的地址到链表中。至此,执行完毕。

事实上,应该是动态分配一个链表节点的缓冲区,里面有LOGGER_BUFFER的变量。不管具体实现流程,大致是上面所说的。

阅读(7031) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~