随笔 - 4  文章 - 0  评论 - 0 
  2008年1月8日

    以往,总理一旦顾不上吃饭,我们就给李维信打电话,请他准备一杯玉米面糊糊或是几个素馅包子,拿在路上吃.这次考虑总理的身体状况,30多小时没休息,胃口肯定不好.我就请李维信准备一碗素汤面.估计汤汤水水的吃着可以舒服些. 
    给李维信打完电话;接着又调车.到办公室请总理出发时,屋里屋外正在乱纷纷找人:"总理呢?谁见总理了?" 
    总理"失踪"了!正有些慌乱,忽然有人说:"哎呀,总理不是说要刮胡子吗?" 
    总理要是用电动刮胡子刀,不会耽误这么久,因为他常是拿着刀上车,在车上顺便就刮了胡子.想到总理的胡子又多又硬,稍长点电动剃须刀就刮不动丁,我就忙朝卫生间找.他也许见电动剃须刀刮不动又用了安全刀片呢…… 
    我在前面走,后面跟了几个人.进门的一刹那,所有人都怔住了;不会说,不会动,甚至停止了呼吸.唉,我们的总理哟!他垂落的左手下,有一条面巾;他微屈的右臂,手里仍虚握着沾有肥皂沫和胡子茬的刮脸刀,他就歪在镜子前边睡着了!他英俊的面孔曾使所有的中国人为之骄傲,现在却变得那么瘦削灰黄;他的眉毛依然威武,双唇仍然露出善良和慈爱,可是他的眼窝却是深深地,深深地沉陷下去…… 
    我们面面相觑,用颤抖的目光互相提醒:别出声,也不要动,让总理睡几分钟,哪怕是多睡几秒……可是,心血翻呀翻,翻上了壅塞的喉咙.有人用手捂住了脸,有人不停地朝上眨眼睛;我们只能让泪水在眼圈里悄悄地转,让泪水往心里默默地流. 
    就这么一屋子人静悄悄地停滞了那么片刻,周恩来双肩一颤,腿失去支撑地猛然一弯,我忙抢上一步扶住他不要摔倒. 
    "哎呀,"周恩来一声轻唤,掀起了眼皮.他与其说看到一屋子人不如说感觉到一屋子人,一边用毛巾擦去脸上的肥皂,用力揉着双眼,一边喃喃:"糟糕,我怎么睡着了呢……"他看一眼表,匆匆向外走:"迟到了,迟到了,这次怪我." 
    "总理!"我们小声叫着追上去,又不敢追到他面前,尾巴一样跟在他身后. 
  因为我们在流泪…… 
    来到新6所,韩念龙等同志已经等侯在那里,迎上总理汇报情况.这时,周恩来用力揉搓一下脸,灰黄的脸孔便奇迹般地恢复了片刻青春的红晕和光彩.我早就发现了这个秘密:只有工作能够使总理显出年轻. 
    李维信轻轻走到周恩来身边:"总理,吃碗面条吧?已经给您准备好了."  
    "不吃了."总理声音沉重地说,带着叹息一般的疲倦.他那威武的眉毛耸了耸.小声说:"你帮我想想法子,看能不能买两块咖啡糖?" 
    "是,总理."李维信匆匆走开,工夫不大便取来两块咖啡糖. 
  总理剥糖纸时,我清楚地看到总理的手指抖得厉害,差点把糖掉地.我要帮忙时,他终于剥下糖纸,把糖放进嘴里.我清楚地看到韩念龙在对面嘴角一阵抽搐,眼圈刷地红了,流水也似地扭开了头. 
  我也低下了头,伯总理看到我夺眶而出的泪水.我知道总理从来不曾吃什么糖块.这次连吃两块,是因为咖啡可以提神. 
  会谈开始了,是与越南总理范文同谈.越南劳动党中央第一书记黎笋和范文同总理从1973年6月4日开始访问我国,一边要援助一边闹矛盾;我们一边不借作出最大的民族牺牲支援他们的抗美救国战争,一边还得听他们的抱怨.这就是胡志明逝世后的中越关系现状.外电当时评论说,黎笋是"亲苏派". 
  会谈中,越方不停地提条件,刚达成一致,他们又出尔反尔地加码,好象我们援助他们不但要无条件,而且应该是无限制地满足一切. 
  会谈十分艰难.周恩来不停地喝茶,但他越来越掩饰不住耗尽血汗之后的极度疲惫,借李维信上水的机会,他小声吩咐:"给我送条湿毛巾." 
  女服务员很快就用托盘送来了湿毛巾.周恩来拿过毛巾,轻轻抖开,垫在右手上,用力擦脸,在额头和眼窝的部位反复擦拭按摩,然后放回托盘上,哑声说:"谢谢." 
  女服务员的目光从周恩来的脸孔上一掠而过,她不敢多看.周恩来刚刚擦拭过的脸孔又恢复了光彩,但那湿漉漉的光彩有多少是水,又有多少是汗?当他用力按摩额头时,他是怎样艰难地从全身每一个细胞里挤压搜索聚集残剩的最后一些血液和热力啊1女服务员嘴角一抿,迅速垂下眼帘退出来,她是在强忍住自己的泪水.  
  不到10分钟,周恩来又用眼色讨毛巾.他常常用眼色指挥调动工作人员,早已形成默契.女服务员再次上毛巾时,他小声请求:"要热的,热一点." 
  第三次上来了热毛巾.周恩来一边倾听范文同的喋喋不休,一边将热毛巾用力按在额头上,片刻,迅速而有力地在脸上搓几下,将毛巾还给服务员,小声嘱咐:"再热些,要烫的." 
  女服务员退下不远,便听到了周恩来的声音.他与范文同会谈的声音始终那么清朗流利,句句反应敏捷,字字切中问题实质. 
  可我们所有的工作人员都越来越不安,心里抱怨范文同没完没了,不看看我们的总理累成了什么样子?但凡有点精神,何至于10分钟一次热毛巾擦脸?但我们不能议论,只是互相传递忧虑不安的目光.偏偏这时,女服务员过来了,向李维信小声报告:"总理要烫毛巾……" 
  李维信牙齿咬一咬下唇,山东大汉那种铜钟般的嗓门竟变得像姑娘的声音一样温柔:"那就用,用开水……用开水涮毛巾……啊?" 
  女服务员始终不曾抬头,望着自己的鞋尖喃喃;"再,再找一个人上毛巾吧." 
  "怎么了?" 
  "我,我受不了了……"女服务员哭了.四周围顿时响起一片唏嘘声. 
  李维信抽响鼻子,用力眨着泛红的两眼,驱散泪水,喉结滚动着,终于喘上一口气,用一种鼻音喃喃的极温和极富感情的口气说:"再说,再说我打你……快去吧." 
  服务室里,两名女服务员用滚开的水为周恩来涮毛巾,腾腾的蒸汽凝聚在睫毛上,眼圈里又有珠泪,端了毛巾望会议室,灯光下便显得五彩斑澜.周恩来在倾听范文同讲话时,将热气逼人的毛巾抖开,灼自己的额头,眼窝,脸颊,脖颈……放下毛巾后,便又开始回答问题,解释情况,阐明道理. 
  会谈从夜里2点一直进行到旭日东升.其间,每隔10分钟便由服务员送上一次开水涮过的毛巾,这是当时在场十几位同志看着表掌握,亲眼目睹,可以完全作证的一次工作场面. 
  "好了,不要涮了."李维信朝服务室里吩咐:"总理马上要走,你们……怎么了,你们,怎么了?" 
  两位女服务员没有像往常那样丢下手里的活儿,追出去送周总理离开.她们俩丢下毛巾,放下开水瓶,面对面垂了头站立,各自捧了双手怔怔地出神. 
  "什么毛病,你们这是……"李维信走近两步,突然住了嘴.两位少女笋一般嫩的手,如今红得像他家乡出产的那种小水萝卜,手指和掌缘烫起一串晶明透亮的小水泡,并且闪闪地泛出光来. 
  "哎呀,烫这么多泡,"李维信皱一皱眉,他不善于跟女孩子讲什么体贴话,有些结巴:"你,你们辛苦了,也,也是为工作么……" 
  两位女服务员仍然是一动不动地捧着手,手在颤,眼角在颤,嘴唇也在颤. 
  "总理……" 
  一声哀哀地轻唤,两名女服务员压抑已久的哭声便挣脱喉咙的束缚,一下子灌满服务室,传入空荡荡的会议室,久久不息地回荡着.于是,李维信这位170斤重的山东汉子也垂下头哭了,在场的人没有一个不是泪流满面…… 
  6月12日,中越联合公报发表. 
  越南党政代表团走后,总理的工作情况被***得知.6月20日,邓大姐向我们全体工作人员传达了那条"最高指示": 
  请恩来同志节劳,不可大意; 
  周恩来是怎样"节劳"的呢?那情景写三本书也写不完.从总理的工作日历和我们的日记就可以看出基本情况. 
  从1974年1月1日到6月1日,这住院前夕的5个月,除了到医院检查病情和治疗外,他总共抱病工作139天.这139天中,工作达18小时以上的有130天2剩余的9天无一不超过10小时以上. 
  如果以小时论,总理抱病工作的5个月,比实行8小时工作制的一般干部工人在一年里的全部工作时间还要长. 
  正是这个原因,我们的日记不能以大自然的一天记,只能以"周恩来的一天"记. 
  周恩来的一天有多长?说不准.随便举他住院前的3个例子:1974年2月9日凌晨4点至2月12日凌晨4点三刻: 
  ……到了11日夜,他还是不能休息,晚上又安排了几个会.第二个会议开始时,他终于累得犯了病,就站起来用椅背顶住腹部继续听汇报.大家不知道他已连续工作近50小时,请他坐下听.他低声说:"我不能坐,一坐下就会睡着……"1974年3月6日下午3点至1974年3月7日中午12点半:
……他工作12小时后,发生缺氧病状,体力实在支撑不住了,躺到床上吸氧,边吸氧边批看文件达9个半小时……1974年5月6日下午4点至8日凌晨4点半: 
  他连续工作18小时后,刚睡下40分钟就被叫到钓鱼台……以后又工作10多个小时,一直到8日凌晨4点半. 
  他又出现严重的缺氧病状,这已经是第4次了…… 
  周恩来的一生可以说都是在这种连续的大工作量中度过,本不足为奇.但是1974年这5个月不同,他的病情已相当严重,每日大量便血,多的时候能达到上百cc,就像直接便血水似的,看着惊心动魄,忍不住泪.他以古稀之年就是这样一边输血吸氧一边便血坚持着健康人无法负担的工作量.当时卫士和医务人员累病三四个,都是比他年轻二三十岁的健康同志,又是轮班跟随他他怎么能不累倒呢? 
  从这个意义上讲,总理确实是累死的. 
  总理也曾讲过伤感的话,我听到过3次: 
  他曾望着整日辛劳的花工老周师傅,用一种苦涩的声音感叹:"唉,咱们西花厅就是我们两个姓周的人最辛苦了……" 
  他曾坐在马桶上批阅文电急件,一小时完不了,终于叹口气说:"我成了一个语文教员,天天在那里改卷子……" 
  有一次开会后,坐车回西花厅.车停好后,他几次动不了身,钻不出车,内我们把他扶出车.下车离办公室只有30几米的路,他自己都走不了,需要我们架着他走. 
  "我太疲乏,"总理歉意地望望我们,身体虚软地下坠着,我们不得不尽力架住他.他脸上掠过一丝凄凉的笑:"让我喘息一下……" 
  "总理!"我轻轻叫一声,赶紧扭开脸.我实在无法忍住流淌的泪.记得每位新到总理身边工作的同志,都要听到邓大姐——声:嘱咐:"总理走路很快,你们要跟紧,不要跟丢了." 
  那个走路生风,行动敏捷洒脱的总理哪里去了?现在他已经无法独自走完30米…… 
  "好了,我们走."总理喘息片刻之后,小声吩咐.我们架着他进屋,要扶他去卧室,他坠着身体不肯去,气虚地说:"到办公室,去办公室." 
  我不再掩饰泪水,两眼湿漉漉地望着总理灰白色的脸孔哭道:"总理,求求你了,休息休息吧,恢复一下体力……" 
  "你叫我什么?总理."我们那亲敬可爱的好总理,他一句一喘地望着我说:"总理,总理.我是这个国家我是全体人民的总理啊,现在国家这个样子我不管谁管?我怎么休息得了啊……" 
  就这样,我们把总理架到了办公桌前.他两手抖抖地拿起办公袖套,我们忙帮他套好,然后扶他在办公椅上坐下来…… 
  总理这样拼命操劳,首先是为了维护国家使之免遭覆灭;同时为了不使领导权落入江青一伙人手中,为了遏止来势凶猛的"批林批孔"运动不要再度演变成"文化大革命"初期那样动乱不堪的局面. 
  从1973年冬开始,由于大量便血,总理每半月或一月就要接受一次输血.有一天下午6点多钟,王洪文让秘书来电话说,晚上要开政治局会,要总理确定时间,"以便江青同志那里好安排其他事情".当时总理正在输血,电话是秘书纪东同志接的,他说:"总理正在治疗,可否半个小时后再商量?" 
  片刻,那边请示了王洪文,回答说:"必须立刻定下来." 
  连毛主席找总理还要问问总理是否休息?如果休息就过两个小时再找.可是这些"得志便猖狂"的"爆发户",就是这样狂妄不可一世.我们只好悲愤地看着医护人员为总理拔下了输血的针头…… 
  到1974年的5月底,周恩来身体已经极度虚弱,随时可能发生休克.在办公桌前只要一坐就站不起身了,非有人搀扶不可. 
  但他仍然坚持按原定计划于5月29日与马来西亚总理拉扎克举行正式会谈,讨论两国建交问题.当时医务人员就守候在门外,随时准备抢救.31日,他又同拉扎克分别代表本国政府签署了中马建交公报.人们见到的周恩来仍然是那么安详稳重,从容不迫.可谁能知道,他是接受输血后才进行了这次重大活动. 
  签字后,总理向秘书口授了"6月1日后对送批文件的处理意见",将各项工作都责任到位地作了具体安排. 
  1974年6月1日,周恩来把桌上所有文件都清理完毕,交待清楚,然后在我们的搀扶下立起身,摘下了套在小臂上的蓝布工作袖套.这两头缝有松紧带的袖套曾伴他度过无数不眠之夜,批阅过多少文件,已经深有感情.我见他把袖套放在桌面上,再用手轻轻地,轻轻地抚平,小心翼翼叠整齐,目头在上边停留几秒,眼圈忽然一红,胸脯猛地起伏一下,将头迅速扭向了一边. 
  于是,我们都伤心地低下了头. 
  周恩来离开了那把坐了20多年的办公椅,我们追随着左右扶持;他在屋中站住脚,环顾一圈,默默地向这里的一切告别.他的目光在办公用具上留恋地往返,终于转向墙壁上的图表,目光忽然闪烁一下,随即又黯淡下来.我随他的目光望去,心战栗着抽缩起来. 
  我看到了那张食管癌高发区发病分布图. 
  于是,一种难忍的痛楚从我心头绞出一滴滴的泪珠,盈满眼眶,朦胧了我的视线.多少往事闪烁着从那膘陇中浮出…… 
  "李冰,李冰同志来了没有?"周恩来在人民大会堂一个会议厅的主席台上朗声问. 
  "来了."前排站起一位朴素端庄的女同志.她是日坛医院的负责人. 
  "李冰同志,你们日坛医院那么多病人,你长期搞肿瘤防治,找没找出原因?" 
  也许是太激动了,也许是这个问题很复杂,不是几句话能讲清的,李冰张一张嘴,声音有些犹豫:"这里原因很多……"但她心情是激动的,脸上泛出红光. 
  "癌症不是地方病,而是一种常见病."周恩来脸上是那种既亲切又严肃的微笑,做了一个摆手动作:"不单是林县食管癌多,西北也多.你说肿瘤的原因很多,要找出主要矛盾来嘛." 
  李冰激动地点点头. 
  "吴桓兴,"周恩来又点日坛医院的另一位负责人,"你这辈子找不出肿瘤的原因来?要树雄心,立壮志,在这一生中攻克癌症么.我看,你们还是到下边去调查好……" 
  于是,医学科学院的科研人员下到河南林县走村串户调查食管癌的发病情况,后来又查遍太行山周围.181个县,那张食管癌高发区发病分布图就是这次调查研究的成果之一.然而谁又料想到,事隔不到一年,癌症竞侵害到总理自己身上. 
  现在,他也不得不离开他工作25年的西花厅,离开他的办公室了……

posted @ 2008-01-08 13:33 小弱 阅读(98) | 评论 (0)编辑
  2007年12月27日

  猎猎北风入九天,
  苍苍暮色忆华年。
  滚滚红尘思归雁,
  漫漫人生路三千!


  今年的冬天有点冷,好在春天就要来了。

  海内存知己,天涯若比邻,兄弟们一路走好!
posted @ 2007-12-27 12:42 小弱 阅读(68) | 评论 (0)编辑
  2007年12月12日
CREATE PROCEDURE testPro
AS
    
/* ------- 事务开始 ---------- */
    
BEGIN TRANSACTION tran_test

    
/* -------- 保存事务 ----------*/
    
SAVE TRANSACTION tran_test

        
/* -------- 数据操作 ---------*/
        
INSERT [table1] ( [content] ) VALUES ( '43332' )

    
/*---------- 提交事务 ------------*/
    
COMMIT TRANSACTION tran_test

    
/*--------- 判断是否有错误 ----------*/
    
IF ( @@ERROR <> 0 )
    
BEGIN
        
/*---------- 自定义错误输出 ----------*/
        
RAISERROR'Insert data error!',16,1 )
        
/*-------- 事务回滚 --------*/
        
ROLLBACK TRANSACTION tran_test
    
END
    
    
/*------- 判断事务数是否大于0 -----------*/
    
IF ( @@TRANCOUNT > 0 )
    
BEGIN
        
/*-------- 事务回滚 --------*/
        
ROLLBACK TRANSACTION tran_test
    
END
GO


这个在网上流传的存储过程事务举例我也用过,可是今天拿出来一看,已经提交的事务还能回滚吗?

从直观上就是错误的,俺以为其中另有“隐情”,于是作了个测试,测试代码如下:

先建了一个表,并向其中添加了约束:

USE [test]
GO
/****** 对象:  Table [dbo].[salary]    脚本日期: 12/12/2007 14:24:47 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[salary](
 [id] [int] IDENTITY(1,1) NOT NULL,
 [salary] [real] NULL
) ON [PRIMARY]

GO
ALTER TABLE [dbo].[salary]  WITH NOCHECK ADD  CONSTRAINT [t1] CHECK  (([salary]>=(1) AND [salary]<=(1)))
GO
ALTER TABLE [dbo].[salary] CHECK CONSTRAINT [t1]


然后新建了一个存储过程:

USE [test]
GO
/****** 对象:  StoredProcedure [dbo].[tt]    脚本日期: 12/12/2007 14:25:44 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:  <风景年华>
-- Create date: <2007-12-12>
-- Description: <test>
-- =============================================
CREATE PROCEDURE [dbo].[tt]
 -- Add the parameters for the stored procedure here
AS
BEGIN
 -- SET NOCOUNT ON added to prevent extra result sets from
 -- interfering with SELECT statements.
 SET NOCOUNT ON;

    -- Insert statements for procedure here
 begin tran
  save tran test
  insert salary values (5)
 
 if (@@error<>0)
  begin
   print '111'
   rollback tran test
  end
 commit tran

 END

再建一个存储过程:

USE [test]
GO
/****** 对象:  StoredProcedure [dbo].[tt]    脚本日期: 12/12/2007 14:25:44 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:  <风景年华>
-- Create date: <2007-12-12>
-- Description: <test>
-- =============================================
CREATE PROCEDURE [dbo].[tt1]
 -- Add the parameters for the stored procedure here
AS
BEGIN
 -- SET NOCOUNT ON added to prevent extra result sets from
 -- interfering with SELECT statements.
 SET NOCOUNT ON;

    -- Insert statements for procedure here
 begin tran
  save tran test
  insert salary values (5)
 
  commit tran

if (@@error<>0)
  begin
   print '111'
   rollback tran test
  end

 END

两次测试结果:
1.

消息 547,级别 16,状态 0,过程 tt,第 17 行
INSERT 语句与 CHECK 约束"t1"冲突。该冲突发生于数据库"test",表"dbo.salary", column 'salary'。
语句已终止。
111

(1 行受影响)

结果中输出了  111

2.

消息 547,级别 16,状态 0,过程 tt1,第 17 行
INSERT 语句与 CHECK 约束"t1"冲突。该冲突发生于数据库"test",表"dbo.salary", column 'salary'。
语句已终止。

(1 行受影响)

结果中没有输出  111  表明没有执行存储过程

测试环境:sql  server  2005 express

这是另外一个示例:

1,SqlServer存储过程的事务处理
一种比较通用的出错处理的模式大概如下:
Create procdure prInsertProducts
(
 @intProductId int,
 @chvProductName varchar(30),
 @intProductCount int
)
AS
Declare @intErrorCode int
Select @intErrorCode=@@Error
Begin transaction
 if @intErrorCode=0
   begin
     -insert products
     insert products(ProductID,ProductName,ProductCount)
     s(@intProductId,@chvProductName,@intProductCount)
     Select @intErrorCode=@@Error --每执行完一条t-sql语句马上进行检测,并把错误号保存到局部变量中
   end
 if @intErrorCode=0
   begin
     -update products
     update products set ProductName='MicroComputer' where ProductID=5
     Select @intErrorCode=@@Error
   end
if @intErrorCode=0
   commit transaction
else
   rollback transaction

 Return @intErrorCode --最好返回错误代号给调用的存储过程或应用程序

2,.Net中使用事务处理
SqlConnection myConnection = new SqlConnection("Data Source=localhost;Initial Catalog=Northwind;Integrated Security=SSPI;");
myConnection.Open();

SqlTransaction myTrans = myConnection***ginTransaction(); //使用New新生成一个事务
SqlCommand myCommand = new SqlCommand();
myCommand.Transaction = myTrans;

try
{
myCommand.CommandText = "Update Address set location='23 rain street' where userid='0001'";
myCommand.ExecuteNonQuery();
myTrans.Commit();
Console.WriteLine("Record is udated.");
}
catch(Exception e)
{
myTrans.Rollback();
Console.WriteLine(e.ToString());
Console.WriteLine("Sorry, Record can not be updated.");
}
finally
{
myConnection.Close();
}


说明:在SqlServer中,每条Sql语句都作为一个事务来执行,所以无论在存储过程,还是在.net代码中使用,执行单条Sql语句没有必要使用事务处理,上面只是为了简化表达而对单条Sql语句使用事务处理



这就是俺的测试  初学sql  欢迎拍转

posted @ 2007-12-12 14:34 小弱 阅读(148) | 评论 (0)编辑
  2007年12月3日
在某网站上看到这篇文章,说实话,不太确定其中的一些说法(对内存映射,一直有点模糊)。放在这里,见仁见智,希望大家谈谈自己的看法。

在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。

  栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区。里面的变量通常是局部变量、函数参数等。

  堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。

  自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生命的。

  全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。

  常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(当然,你要通过非正当手段也可以修改,而且方法很多,在《const的思考》一文中,我给出了6种方法)

  明确区分堆与栈

  在bbs上,堆与栈的区分问题,似乎是一个永恒的话题,由此可见,初学者对此往往是混淆不清的,所以我决定拿他第一个开刀。

  首先,我们举一个例子:

void f() { int* p=new int[5]; }

  这条短短的一句话就包含了堆与栈,看到new,我们首先就应该想到,我们分配了一块堆内存,那么指针p呢?他分配的是一块栈内存,所以这句话的意思就是:在栈内存中存放了一个指向一块堆内存的指针p。在程序会先确定在堆中分配内存的大小,然后调用operator new分配内存,然后返回这块内存的首地址,放入栈中,他在VC6下的汇编代码如下:

00401028 push 14h
0040102A call operator new (00401060)
0040102F add esp,4
00401032 mov dword ptr [ebp-8],eax
00401035 mov eax,dword ptr [ebp-8]
00401038 mov dword ptr [ebp-4],eax

  这里,我们为了简单并没有释放内存,那么该怎么去释放呢?是delete p么?澳,错了,应该是delete []p,这是为了告诉编译器:我删除的是一个数组,VC6就会根据相应的Cookie信息去进行释放内存的工作。

  好了,我们回到我们的主题:堆和栈究竟有什么区别?

  主要的区别由以下几点:

  1、管理方式不同;

  2、空间大小不同;

  3、能否产生碎片不同;

  4、生长方向不同;

  5、分配方式不同;

  6、分配效率不同;

  管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memory leak。

  空间大小:一般来讲在32位系统下,堆内存可以达到4G的空间,从这个角度来看堆内存几乎是没有什么限制的。但是对于栈来讲,一般都是有一定的空间大小的,例如,在VC6下面,默认的栈空间大小是1M(好像是,记不清楚了)。当然,我们可以修改:

  打开工程,依次操作菜单如下:Project->Setting->Link,在Category 中选中Output,然后在Reserve中设定堆栈的最大值和commit。

  注意:reserve最小值为4Byte;commit是保留在虚拟内存的页文件里面,它设置的较大会使栈开辟较大的值,可能增加内存的开销和启动时间。

  碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出,在他弹出之前,在他上面的后进的栈内容已经被弹出,详细的可以参考数据结构,这里我们就不再一一讨论了。

  生长方向:对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于栈来讲,它的生长方向是向下的,是向着内存地址减小的方向增长。

  分配方式:堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。

  分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多。

  从这里我们可以看到,堆和栈相比,由于大量new/delete的使用,容易造成大量的内存碎片;由于没有专门的系统支持,效率很低;由于可能引发用户态和核心态的切换,内存的申请,代价变得更加昂贵。所以栈在程序中是应用最广泛的,就算是函数的调用也利用栈去完成,函数调用过程中的参数,返回地址,EBP和局部变量都采用栈的方式存放。所以,我们推荐大家尽量用栈,而不是用堆。

  虽然栈有如此众多的好处,但是由于和堆相比不是那么灵活,有时候分配大量的内存空间,还是用堆好一些。

  无论是堆还是栈,都要防止越界现象的发生(除非你是故意使其越界),因为越界的结果要么是程序崩溃,要么是摧毁程序的堆、栈结构,产生以想不到的结果,就算是在你的程序运行过程中,没有发生上面的问题,你还是要小心,说不定什么时候就崩掉,那时候debug可是相当困难的:)
posted @ 2007-12-03 20:24 小弱 阅读(118) | 评论 (0)编辑