|
|
用户名:sukiyaky 笔名:sukiyaky 地区: 北京-海淀区 行业:本科 |
| 日 | 一 | 二 | 三 | 四 | 五 | 六 |
一直有云里雾里的感觉,其实人活的混沌未必不是件好事情,也奇怪,有时候人很轻易的就忘记了一些事情,有的事情却怎么也忘不了,周而复始的在你的思绪中穿梭来去,是美丽的吧,或许它曾经是丑陋的,也是幸福的吧,或许它曾经让你是痛苦的,有回忆终归还是好的......
内存对齐问题
十月 19th, 2006
没看C标准的相关部分,懒的,没查e文的,觉得中文的讲得还可以。(用关键字“C byte alignment”)
搜了一些文档,大概有了了解,又是体系结构不统一、实现不统一等等造成的,sigh。
下面内容大部分从不同的url里摘出来的,不去细分谁是谁了。
———–
不对齐的数据存取在x86上影响速度,因为在不对齐的时候,对一个不超过32位的变量的访问,可能需要超过1次的内存读取。
对齐即是多分配一些字节,填充无用数据。填充的位置可以是结构的中间和尾端。主要遵循的原则,总而言之就是一个:结构以其成员的最大占位为基本单位分配空间,将所有变量逐个填充进去,填不满的补足,直到结构的最后一个变量。
这样,同样的变量成员,放置的先后顺序不一样,结构空间可能也不一样。所以一般遵循把大尺寸的数据变量放在前面,以节约内存:)
编译选项和编译指令(#pragma pack)可以去用户自定制对齐规则。
对齐规则:
1、数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。
2、结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。
3、结合1、2颗推断:当#pragma pack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。
另外就是,x86架构(不清楚是仅硬件相关还是跟os也有关系,好像win和linux都这样的)中,地址空间的布局中,堆向高地址增长,栈向低地址增长。
对于连续的两个栈上变量,发现不同编译器对局部变量的地址分配还有有些区别的。vc6(cl),对单个变量,不管是1个byte,还是2个byte,均分配4个byte的空间,而gcc对单个变量,也是采用压缩的对齐方式。两个连续的1 byte,如果可能,就放在同一个4byte之内了。(在同一台x86的机器上测试过,win2k, gcc3.3.1(MinGW), vc6)
内存泄露问题小补充
1. 常发性内存泄漏。发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。
2. 偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。
3. 一次性内存泄漏。发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块仅且一块内存发生泄漏。比如,在类的构造函数中分配内存,在析构函数中却没有释放该内存,所以内存泄漏只会发生一次。
4. 隐式内存泄漏。程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。
从用户使用程序的角度来看,内存泄漏本身不会产生什么危害,作为一般的用户,根本感觉不到内存泄漏的存在。真正有危害的是内存泄漏的堆积,这会最终消耗尽系统所有的内存。从这个角度来说,一次性内存泄漏并没有什么危害,因为它不会堆积,而隐式内存泄漏危害性则非常大,因为较之于常发性和偶发性内存泄漏它更难被检测到。
内存泄漏问题
浅谈内存泄漏(一)
对于一个c/c++程序员来说,内存泄漏是一个常见的也是令人头疼的问题。已经有许多技术被研究出来以应对这个问题,比如Smart Pointer,Garbage Collection等。Smart Pointer技术比较成熟,STL中已经包含支持Smart Pointer的class,但是它的使用似乎并不广泛,而且它也不能解决所有的问题;Garbage Collection技术在Java中已经比较成熟,但是在c/c++领域的发展并不顺畅,虽然很早就有人思考在C++中也加入GC的支持。现实世界就是这样的,作为一个c/c++程序员,内存泄漏是你心中永远的痛。不过好在现在有许多工具能够帮助我们验证内存泄漏的存在,找出发生问题的代码。
内存泄漏的定义
一般我们常说的内存泄漏是指堆内存的泄漏。堆内存是指程序从堆中分配的,大小任意的(内存块的大小可以在程序运行期决定),使用完后必须显式释放的内存。应用程序一般使用malloc,realloc,new等函数从堆中分配到一块内存,使用完后,程序必须负责相应的调用free或delete释放该内存块,否则,这块内存就不能被再次使用,我们就说这块内存泄漏了。以下这段小程序演示了堆内存发生泄漏的情形:
void MyFunction(int nSize)
{
char* p= new char[nSize];
if( !GetStringFrom( p, nSize ) ){
MessageBox(“Error”);
return;
}
…//using the string pointed by p;
delete p;
}
例一
当函数GetStringFrom()返回零的时候,指针p指向的内存就不会被释放。这是一种常见的发生内存泄漏的情形。程序在入口处分配内存,在出口处释放内存,但是c函数可以在任何地方退出,所以一旦有某个出口处没有释放应该释放的内存,就会发生内存泄漏。
广义的说,内存泄漏不仅仅包含堆内存的泄漏,还包含系统资源的泄漏(resource leak),比如核心态HANDLE,GDI Object,SOCKET, Interface等,从根本上说这些由操作系统分配的对象也消耗内存,如果这些对象发生泄漏最终也会导致内存的泄漏。而且,某些对象消耗的是核心态内存,这些对象严重泄漏时会导致整个操作系统不稳定。所以相比之下,系统资源的泄漏比堆内存的泄漏更为严重。
GDI Object的泄漏是一种常见的资源泄漏:
void CMyView::OnPaint( CDC* pDC )
{
CBitmap bmp;
CBitmap* pOldBmp;
bmp.LoadBitmap(IDB_MYBMP);
pOldBmp = pDC->SelectObject( &bmp );
…
if( Something() ){
return;
}
pDC->SelectObject( pOldBmp );
return;
}
例二
当函数Something()返回非零的时候,程序在退出前没有把pOldBmp选回pDC中,这会导致pOldBmp指向的HBITMAP对象发生泄漏。这个程序如果长时间的运行,可能会导致整个系统花屏。这种问题在Win9x下比较容易暴露出来,因为Win9x的GDI堆比Win2k或NT的要小很多。
内存泄漏的发生方式:
以发生的方式来分类,内存泄漏可以分为4类:
1. 常发性内存泄漏。发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。比如例二,如果Something()函数一直返回True,那么pOldBmp指向的HBITMAP对象总是发生泄漏。
2. 偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。比如例二,如果Something()函数只有在特定环境下才返回True,那么pOldBmp指向的HBITMAP对象并不总是发生泄漏。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。
3. 一次性内存泄漏。发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块仅且一块内存发生泄漏。比如,在类的构造函数中分配内存,在析构函数中却没有释放该内存,但是因为这个类是一个Singleton,所以内存泄漏只会发生一次。另一个例子:
char* g_lpszFileName = NULL;
void SetFileName( const char* lpcszFileName )
{
if( g_lpszFileName ){
free( g_lpszFileName );
}
g_lpszFileName = strdup( lpcszFileName );
}
例三
如果程序在结束的时候没有释放g_lpszFileName指向的字符串,那么,即使多次调用SetFileName(),总会有一块内存,而且仅有一块内存发生泄漏。
4. 隐式内存泄漏。程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。举一个例子:
class Connection
{
public:
Connection( SOCKET s);
~Connection();
…
private:
SOCKET _socket;
…
};
class ConnectionManager
{
public:
ConnectionManager(){
}
~ConnectionManager(){
list::iterator it;
for( it = _connlist.begin(); it != _connlist.end(); ++it ){
delete (*it);
}
_connlist.clear();
}
void OnClientConnected( SOCKET s ){
Connection* p = new Connection(s);
_connlist.push_back(p);
}
void OnClientDisconnected( Connection* pconn ){
_connlist.remove( pconn );
delete pconn;
}
private:
list _connlist;
};
例四
假设在Client从Server端断开后,Server并没有呼叫OnClientDisconnected()函数,那么代表那次连接的Connection对象就不会被及时的删除(在Server程序退出的时候,所有Connection对象会在ConnectionManager的析构函数里被删除)。当不断的有连接建立、断开时隐式内存泄漏就发生了。
从用户使用程序的角度来看,内存泄漏本身不会产生什么危害,作为一般的用户,根本感觉不到内存泄漏的存在。真正有危害的是内存泄漏的堆积,这会最终消耗尽系统所有的内存。从这个角度来说,一次性内存泄漏并没有什么危害,因为它不会堆积,而隐式内存泄漏危害性则非常大,因为较之于常发性和偶发性内存泄漏它更难被检测到。
这个汗~~~~留着备用,郁闷的时候看看不错
做这样的男人
1、如果她背叛了你,而你想起她正在和某男亲热而撕心裂肺时,告诉自己:生活属于强者,想赢得一切,先赢得自己。”相信不远的将来你将为今天的分手而庆幸。告诉她“我很好,也祝你快乐”。
2、虽然你刻骨铭心的爱她,但当分手已成定局的时候,不要伤害自己,身体是自己的。更不要酗酒然后大哭大嚷说:“我会让你后悔的”,记住这是弱者的表现。如果你真的很伤心,可以一个人到高山上,或大海边,静静的想一个晚上,然后对自己说:“我就是我”
3、当你感觉失去她就失去一切的时候,不要灰心。记着:生活不会让一个自信的男人失去未来。只要你不沉沦,没有人能改变你的明天。
4、时间能改变一切,不要让记忆占据你的生活,过去了就让它过去了。就像丘吉尔讲的,“永远的为了现在和过去在那里纠缠不清的话,那你很可能就失去未来”。过去已不属于你,而未来却真真切切是你的。
5、不要想象她日后的生活,虽然你爱她,但她如何生活已经与你没有多大的关系,如果你总不能摆脱感情的泥潭,步入自己的正轨。那她除了觉得和你分手正确外,还会更加瞧不起你。
6、分手后不要刻意表现出你多么的无所谓,要知道你此时的表现更印证了你的心虚,一个心虚的男人不但博得不了她的同情,更会影响你将来的她对你的看法。踏踏实实的做好你通往目标上的每一件事,才是你成熟的表现。
7、女人爱强者,虽然这句话描写西方女人更合适。但也许有人会碰到以这句话为借口分手的女人,她们崇尚金钱、崇尚外表、崇尚地位。如果她不屑一顾的抛弃了你,请你不屑一顾的送她走。因为钱,她抛弃了你,你要是个汉子,你要拼命的赚钱,赚钱不是要博回她的芳心,而是要为你将来爱你的老婆和孩子撑起一片美丽的天空。
8、如果你用伤害自己的方式来证明你的胆识而赢得她的同情的话,请你放弃这样愚蠢的想法,胆识不是一时激动的决定,即便感情能挽回,也是暂时的,或许造成分手的原因是来自于你自己。胆识与信任来自于生活中的点点滴滴,而不是一时的心血来潮。
9、不要临分手还表现的多么的爱你的女人,她有了别的男人,劝你不要把与某某人决斗挂在嘴边,更不要去做,既然她选择了别的男人,她就不值得你去为她再去做什么。记住:值得你去决斗的女人只有两个,一个是你的母亲遇到外来的生命威胁,另一个是刻骨铭心爱你的老婆或女友遭到另一个男人的挑衅。
10、笑到最后的才是强者。如果你能掩饰住内心巨大的痛苦而爽朗的笑出你内心的积怨,或者能诡秘的微笑着面对你的任何对手,我知道你是强者
回归
好久不上来写东西,其实就没怎么写东西的,偶然在baidu上搜了搜“Sukiyaky”这个关键词,第一个蹦出来的居然是我的博客《云里雾里》,然后后边跟着一大串到我博客的连接,哈哈,做梦也没有想到啊,这么多的连接居然是因为那几篇考研大纲。想想真的很讽刺的说。
考研,上学,感觉已经是哪么的遥远,虽然偶尔还会怀恋一下那时的生活,偶尔也会意淫一把曾经的梦想,但是现实让我清醒的知道,离那样的生活,已经越来越远,再也回不去了。
加着班,偷偷的写着博客,悄悄的意淫着过去的生活,猛然发现,原来很多的事,都错了,人总是会失去很多,当然也会得到很多,当你为了得到某些东西而决定丢弃某些东西时候,你是否想过,你想得到的真的是你想要的吗?或许没有人会有哪么清楚的去想过,只有在事后权衡的时候才会幡然醒悟,那又怎么样呢,人生本就是一个不断抉择的过程,时间不会给你清醒和反复权衡的机会,永远不要想当初选择另外一条路时会怎么怎么样,唯有将你所抉择的路努力向你想象的方向引导!
人,永远不要把别人作为自己前进的目标,你走的是自己的路,经历的是自己的人生,是好是坏,去品味的都是你自己,别尝试着去体验别人的生活