江边闲话集

04/12/2019

码农如何写好一封邮件(4)

Filed under: 一技之长 — 张太国 @ 12:26

邮箱地址顺序

前面已经说过,需要用Full Name来表示发件者后者是收件者。不知道大家有没有关注到一些细节,如果To或者CC不止一个邮件地址时,当你收到邮件后,有没有观察到邮件To、CC的顺序呢?

这个顺序其实是非常重要的,它代表了当时发件人输入的顺序。

为什么我们关注这个顺序?很简单,这是发件者心理的一种反应。某些情况下,代表的是该邮件接收者主次之分,有时候也代表了你在对方的重要性,这是人的一种本能直观反应。

当你掌握这个技巧后,在某些情况下来揣测发件人的用意或者背后深层次的东西,这种只能具体问题具体分析。

如何把握这个顺序?

首先,需要根据自己的内容,判断接收人都有哪些。如果只有一个人,那无所谓。如果有多个人,需要考虑将问题的直接负责人放到首位。如果多个人都差不多,最好是把职位高一点人放在前面,这是职场里的一些职场逻辑,不赘述,理解就行。

如何在To里合理设置接收人?

先看几个case。

Case #1:To里只包含一个联系人,假说是Bill

这种情况下Bill是接收人,而且唯一的,一般情况下Bill会认真对待这封邮件。

Case #2, To里包含2-3个人,例如除了Bill,还有Emma或是Terry

可能Bill, Emma,Terry都会认真去看这封邮件,但是强烈度就没有case #1那么强了。

Case #3,如果To里包含大于三个接收人,这种情况下更没有人看了。

所以,为了让自己发出去的邮件有很好的feedback,在To里,需要合理安排接收人。如果的确To里有多个人,是需要在正文里点名到谁的,否则你收到的反馈可能会慢一些,甚至接收不到回应,因为大家都认为有可能不是自己的任务。

所以,如果在正文里写Hi Bill,那么Bill需要去take action,如果是”Hi Bill/Emma“,那么Bill 和Emma去take。

这是一些技巧而已,比较好理解。

邮件组

一般来说,在写邮件时,需要将邮件组放在To/CC靠后的位置,毕竟有可能邮件组有很多人,在一般情况下,可以选择相关的组来替代单个人。如果需要将某人单独拧出来,那除了发送给邮件组,也需要发给这个人。

04/10/2019

码农如何写好一封邮件(3)

Filed under: 一技之长 — 张太国 @ 11:06

编写一封专业的邮件,邮件的内容是非常关键的一部分。

拼写

无论是中文还是英文,尽量避免错别字。先说邮件如果出现错别字,会带来哪些影响?

影响个人形象。收件人会认为你不太仔细,不太严谨,为什么发出来的邮件会有错别字呢。这对于严谨的商业合作或多或少造成一些负面影响。在同样的条件下,选择可信赖的人肯定是大家的习惯。

甚至影响公司形象。个人是在公司这个组织下的,虽说不能完全影响到公司,但是在某些情况下,你的失误会造成收件人对公司的看法。

那么怎么去避免呢?可以先看看几个方面:

语法尽量正确,尤其是在写英文时,例如时态,单复数等。

对于一些专有名词,也需要写对。例如这两个词Android、iOS,经常看到写成android、IOS,或者其他形式的,例如Python,也有人写成python,专有词有专有词的写法,这都是一些细节问题,加以注意。

幸运的是,现在的邮件系统都有拼写检查的功能,虽说不能检查出特别高级的问题,但是一些基本问题例如拼写还是可以解决的。

格式

格式也是非常重要的。邮件写的好不好,是否易于阅读,好的格式会帮助不少。

空格,空行,列表等表达形式能够将邮件格式化,提高阅读效率。

空格,一般多处于英文里,标点符号后需要跟一个空格。

例如:Hello Tim, thank you for supporting this project. 我们可以看到Tim后面的逗号后有一个空格,这是一种书写习惯。

空行,也是非常重要,一般用在断语段之间,这样显得每段所表达的内容不一样。清晰易读,尤其是每段内容很多的情况下。

列表有很多,例如数字开头的,radio开头的。无论用哪一个,都会让人读起来特别清晰。我举个例子,为了描述某手机,我们可以这么做,该手机内存8G,ROM128G,配置3000万摄像头,防水等。如果我们改成如下

  1. 内存8G, ROM 128G
  2. 摄像头:3000万
  3. 防水

前后一比较,发现后者看起清晰,阅读起来舒服很多。

需要说明的是,英文和中文顶头不一样。英文时顶格写,中文可以后退2个。我看到好多人写英文和写中文一样,退后2个去写的,这不好。

陈述你的目的

写邮件肯定是有某个目的才去写的,所以要把自己的目的陈述清楚,这样阅读者一看就知道这封邮件的目的。有时候,看见过很多邮件,不把目的描述清楚,让阅读者去猜,去总结,这会降低邮件的沟通效率,前面说过,邮件是为了沟通,如果邮件表述得清楚,是有助于提高效率的。

多用If-then

一般来说,某件事情有多种选择,我们尽量在邮件里提出来。比如下面这段描述:

I would like to confirm if you have time to join the meeting at 15:00 tommorrow. If yes, I will book the meeting today, if no, 17:00 is OK to you? or what is your available timeslot?

这样,能在一封邮件里把各种情况都考虑到那最好了,给对方多一个选择,而且是一个明确的选择。对方至少知道你的态度,如果他认为不合适的,他会主动告诉你他的时间的。

保持邮件专业

例如,在正式商务邮件里,不要开玩笑,不要表达自己的消极情绪,甚至不要使用表情包。

同时,也不要使用一些缩写,例如tmr -> tomorrow. PLZ ->Please等。

有些时候不要用大写,因为这显得有点不友好。例如,CAN YOU REPLY TO ME BY TODAY?。这有点强迫对方似的。

码农如何写好一封邮件(2)

Filed under: 一技之长 — 张太国 @ 11:05

软技能

我们知道,在现在的商业和生活中,邮件其实是一种相对正式的沟通方式,所以我们需要意识到邮件的重要性。这样看来,编写一封专业的邮件是我们程序员需要掌握的一门软技能。

说到软技能,作为码农,大家关注的还是编程、调试等相对专业的技能,我认为这是硬技能,是从事IT行业必须的技能。随着自己越来越资深,软技能的培养是势在必行的,它决定了你在职业发展中上升高度的重要因素之一。

现状

在国内,我并不认为邮件使用的特别普及,尤其是在一些小的公司,觉得写邮件麻烦,甚至交流效率低下。我想说的是邮件有它的重要性,例如topic可描述性,这需要我们在写邮件时思考再思考,还有就是备份,可跟踪性。

国内好多企业都不重视,但是在一些国内外企,大型国企,民营企业,却非常重视,写邮件必须成为一门技能。

下面说说写邮件的一些细节。

邮件地址和全名

有些邮件地址其实是不能很好的标识接收者或者发送者。例如,邮件地址123753@qq.com,我们是无法分清这个邮件地址到底是谁,所以我们需要指定一个名字给他,例如Bill Chen,现在的邮件系统都支持。

除了能让人快速知道是谁,我们在Microsoft Outlook(或是其他邮件系统)的地址字段(TO,CC或BCC等),只需要输入名字即可,在这里我们输入Bill或者Chen都可以快速把Bill Chen的邮箱地址找到,最后地址可能显示的格式为Bill Chen<123753@qq.com>.

问候

简单即可,例如一下几种方式都没有问题:

  1. Greetings
  2. Hi David
  3. David

这些开头,只是为了友好的开头,这样后面的具体内容才可以进行下去。

正式内容

前面一篇文章里,我说过务必注意邮件的格式,会让收件人觉得阅读邮件是一件快乐的事情。

但是有个问题不知大家考虑过没有?如果邮件太长,往往起到的效果并不好,同样会产生压迫感,所以一封长短适中的邮件也很重要。据调查,一封邮件最好不要超过25行,这样才是友好的。所以我们写邮件必须Focus一个Topic,尽量在25行里把Topic描述清楚。

如果你有多个Topic,建议多发几个邮件,每封邮件只包含一个主题。

一封邮件一个主题

那么为什么一封邮件最好只有一个主题呢?

我先举个例子说说我们常见的情况。假说一封邮件有2个主题,发件人与收件人不停的通过邮件交互,来来回回几十条。如果针对这2个Topic不停的交互,假说哪天我们想回顾某个主题,我们不得不去长长的邮件里先得排除另外一主题,最后才能自己想要的内容。这样是很浪费时间的。

另外一个原因是Focus。邮件也是需要Focus,这是我们为了把事情简单化的哲学理念。

03/18/2019

码农如何写好一封邮件(1)

Filed under: 一技之长 — 张太国 @ 12:07

做技术管理做了有些年了,和不同的team、不同的客户打交道也是非常多的,自认为在写邮件这件事情上还是做的还算可以。相反,我发现很多朋友或同行在写邮件上不得要领,或是想写好但是不知道怎么写。今天这篇文章分享我的一些经验,如果反响还不错,这是我最大的动力,我会展开来写。

在我看来,邮件其实文档的一种,所以邮件一个最主要的目的是用来沟通。既然是沟通,那么我们要达到让对方以最快的速度知道你想要表达的意思,这就是中心点,后面这些都是围绕这个主题进行。

当然,邮件是有很多技巧的,熟练使用这些技巧,会让你事半功倍。

邮件种类

先说邮件的种类,一般来说有四种

  1. 无需回复的邮件。这种邮件主要是想告诉收件者一些信息,例如我们平常收到一些报表邮件,部分监控邮件等,这些邮件我们无需回复,知道这些即可。
  2. 查询邮件。这种邮件比较多,你写邮件是想从收件人那里知道一些事情,比如建议,意见或者动作等,希望收件人能够回复你。
  3. 开放式结尾的邮件。主要是一些开放式结尾的邮件,例如保持联系。当然这也是为了将来以后的联系方便,获取进一步的结果或者便利。举个例子,我们想问某个公司的HR有没有职位招聘,HR说暂时没有,你可以说保持联系,以后有的话再发邮件去问,而且最好是基于该邮件去问,这样HR看到邮件的承前启后,知道你是谁,问什么事,不至于太突兀。
  4. 需要采取动作的邮件。这种邮件不仅仅是期望得到你的答复,而是需要得到你的动作。例如,老板发邮件给小明,让他预定一个会议。小明需要将预定好的会议信息回复给老板,包括时间、地点(会议室)、邀请的人物。如果需要电话会议,电话会议的URL、拨入的电话号码和方式。

邮件组成

那么怎么写好一封邮件呢?

首先我们得弄清楚邮件的组成:

  1. To(收件人)
  2. CC
  3. BCC
  4. 邮件主体

一般邮件主体又分为

  1. 邮件标题(Subject Line)
  2. 开场白(Opening Sentence)
  3. 消息体
  4. 结束语

如何写邮件

收件人

收件人是你要发送给谁的,是邮件的直接接收者。可能收件人会有多个,因为他们这几个人都是直接的接收者。

CC

CC一般是指抄送,FYI的目的,让CC的人知道就行了,但是不建议把不太相关的人放到这里,因为绝大部分人只关心和自己有关的事情和邮件。把一些不相关的邮件发送给不相关的人,可能会对方起到骚扰作用。

BCC

密送,既然是密送,在To,CC里的人不知道BCC里的人列表。这个某些情况下非常有用,可以保护一些隐私。举个例子,我收到过很多离职邮件,一般人可能这么写。

发件人:David Cook
收件人:David Cook
主题:Cook's Farwell

我收到这封邮件,说明我是接收人,但是我并不在收件人里,为什么?因为我在BCC里。那么为什么我会在BCC里?可能是发件人为了避免尴尬,省去一些不别要的麻烦。

邮件标题

邮件标题非常重要,这是能够快速了解邮件目的的最直接的信息。试想,一般来说邮件进入我们的收件箱里,都是邮件列表里的一条记录而已,如果你想看具体内容,还得单击或者双击一下该邮件记录。所以,为了让收件人快速理解邮件的主题,邮件标题是最好的入门。

合理的邮件标题会让人省时间,觉得你非常专业。

一般来说,邮件标题没有固定的格式,把事情说清楚就好了。

先看看下面一个例子:

Subject:Meeting
Hi David,I just wanted to remind you about the meeting we scheduled in last Friday, 
do let me know if you can attend it on time. Thanks.
Taiguo Zhang

如果看到这个邮件标题,我们只知道邮件是关于会议的,但是是其他什么事情就不知道。我们可以改一下

Subject:  Reminder of 10:30AM meeting on next Mon(3/18) about Visiting Japan

这样改了之后,一看到邮件就知道是提醒礼拜一的关于访问日本的会议了。

再来一个例子,我们经常做Performance Review,可能要提醒每个员工去做,怎么写呢?较好的例子如下:

Subject[ACTION REQUIRED] Finish your PR's last step before this Friday(3/20)

我在这里加了一个ACTION REQUIRED, 为什么?因为提醒这个是需要你做ACTION,而且大写,说明非常重要。而且必须在礼拜五做完。

 

开场白

一般情况下,开场白还是直接说事儿,让对方明白邮件的意图,因为Subject line已经简单说了,我们可以再说的详细一些。接上面的例子,例如可以如下:

Hi David,I would like to know if you can join the meeting about the visiting Japan at 10:30AM in next Monday, as it is very important for us to make a decision. Then the procedure can move forward,that is helpful to be behind the schedule. If you can't, please DO let us know, then we can make another meeting.

这样我们就把事情说清楚了。

但是如果由一些不太好的消息或者其他,可以先用一些软和点的话做铺垫,然后再把不好的事情说出来,这样在人的感情上会容易接受点。

消息体

主要还是对邮件的主题详细描述,作为主题的支撑,讲事实,讲道理,将为什么要写这封邮件。

同时,邮件的topic最好不要超过一个,这样易于阅读和专注。如果是多个的话,一是分心,二是处理起来略微麻烦一些。

同时,因为消息体可能会很长,为了便于阅读,我们可以做到:

  1. 尽量使用短句,读起来不费劲。
  2. 尽量使用段落
  3. 对于关键点可以加粗
  4. 对于某些句子和词语,可以用颜色,但是慎用。比如红色,红色一般指警告,所以慎用。
  5. 用List,比如:1,2,3…, a,b,c…这种。
  6. 注意使用空格和空行,如果文字堆积到一块,对人有压迫感。如果给出适当空白,会让人放松很多。这有点类似写代码的风格。

结束语

结束语很重要,主要用来:

  1. 总结你的观点
  2. 如果有ACTION,指出对方需要做的ACTION。
  3. 如果有deadline,需要指出Deadline。
  4. 如果不需要Action,写出适合的结束语即可。例如“Thanks for your help on solving this problem.”

签名

上面没说到签名,其实还是要做的。分为2种情况:

公司内部

是指邮件发给公司内部的,大家可能都知道你,写出名字、分机,手机即可。如果大点的公司,需要带上职位,所在部门。

公司外部

如果收件人是客户或者其他人,需要以下信息:

  1. 名字(中文名+英文名)
  2. 职位
  3. 部门
  4. 分机
  5. 手机
  6. 邮箱
  7. 公司的logo,网址,甚至是slogan。
  8. Skpye或QQ或微信,如果需要的话

Disclaimer

在一些公司法律做的比较完善,在邮件最后面会加上一些Disclaimer,主要是为了保护一些相关信息吧。

暂时先写到这里,其实还有好多细节上的技巧问题。例如,

  1. to,cc的联系人怎么加,联系人顺序的问题?
  2. 邮件的语调
  3. 邮件的称呼
  4. 邮件的专业性
  5. 邮件编辑的技巧

09/01/2017

Web安全-隐藏Web Server信息

Filed under: 一技之长 — 张太国 @ 12:09

这是一个非常容易忽略的点。

Web Server的信息包括:

  • Web Server的类型,常见的如Tomcat, Apache Httpd,Ngnix等。
  • 版本信息。即web server的版本信息。

为什么要隐藏这些信息呢?原因很简单,我们非常容易获取web server的软件信息。那么对于攻击者可以做什么呢?我们知道每种软件都是有漏洞的,尤其是对于这些著名的软件。如果出现安全性漏洞,一般都是公开的,而且有些漏洞有详细的复现步骤。

其他web server不在这里例举了。

所以,当攻击者知道web server信息,又加上这对每个漏洞的详细解释,攻击就简单多了。

那么如何隐藏web 容器信息呢?一般来说是可以通过配置解决的。

Apache Tomcat

可以在server.xml里的Connectorserver属性解决。参考https://tomcat.apache.org/tomcat-7.0-doc/config/http.html

Apache HTTPd
security.conf里的ServerSignature Off

08/09/2017

Web安全- Command Injection

Filed under: 一技之长 — 张太国 @ 10:58

Command Injection,是指Web App调用系统命令去实现某些功能,同时因为不安全的web请求数据(例如Form,Cookie,HTTP header等)利用该功能造成一些安全影响。

实例

下面的例子便于理解。

本例子来源https://www.owasp.org/index.php/Command_Injection

下面的PHP代码会引起Command Injection:

<?php
print("Please specify the name of the file to delete");
print("<p>");
$file=$_GET['filename'];
system("rm $file");
?>

我们看看请求和返回。

请求

http://127.0.0.1/delete.php?filename=bob.txt;id

响应

Please specify the name of the file to delete

uid=33(www-data) gid=33(www-data) groups=33(www-data) 

我们可以看到,如果执行web的function id足够大的话,是极有可能把不应该的数据删除了,例如filename为/,同时我们也可以看到该id所在的group。

解决方案

可以尽量使用API。例如上面要删除一个文件,可以使用php语言的api去删除文件,而不是调用OS的rm命令。

如果没有相关的API去调用,一定要调用这些command,务必做好命令的验证。就个人经验看,验证允许的command比验证不允许的command要简单一些。

03/08/2017

软件开发规则

Filed under: 一技之长 — 张太国 @ 14:26
最后版本: rev 5
最后更新: 2017-04-21

设计

  1. 注重软件设计。
  2. High Available需要考虑。
  3. Geo Redundancy也需要考虑,如果设计web的话。
  4. 考虑软件的需求,有无可能复杂化,定制化,这决定了软件架构,
  5. 将需求详细化,但实现时简单化。
  6. 数据库主从结构,Replication,数据一直等。
  7. web的安全性方面是必须考虑的。
  8. 软件都是逐步迭代的,为了让后期迭代的成本更小,起点最好高一些。
  9. 事先定义软件的版本管理。
  10. 站在使用者的角度去思考。
  11. 解放思想,考虑问题站在高一点的位置。
  12. 防止过度设计。


Coding

  1. 一个文件代码不要太多,1K行左右,一个函数也不同太多,100行左右,如果太多的话,就应该考虑如何去分拆了。
  2. 代码一开始就要考虑模块化。
  3. 代码可重用性。
  4. 代码不能太耦合。
  5. 对于异常case务必写日志,不要认为捕获了就OK了。
  6. 良好的代码目录结构。
  7. 对于SQL等一些reserved keywords建议用大写,例如SELECT * FROM <tbl-name> WHERE field1=v AND field2 = v2
  8. 代码格式上须易于阅读,空格,空行等是必要的。Java有Java的代码规范,可以作为参考准则。
  9. 注释需要合理,不在于多,而在于精。对业务复杂的业务逻辑,加适当的注释会锦上添花。
  10. 代码格式可以利用一些专业化的工具进行检测,例如Sonar,JSLint等。
  11. 写代码是软件开发里非常简单的事情,但是做好不容易。基础非常重要。态度谦逊,借鉴优秀人员的代码,避免自己的不足。
  12. 一开始就要写好,不要以后面可以重构当借口。
  13. 对于web开发,安全性非常重要。可以写完后用安全扫描工具(例如AppScan等)进行扫描。掌握经验,在后面的coding种尽量去避免。
  14. 尽量将问题或需求想的全面,实现时根据实际情况可以取舍。
  15. 设计准备好了才可以写代码。
  16. 对于异常case多处理,不要认为发生的可能性不大。
  17. 尽量让代码的适应性强一些,考虑一些配置来适应未来的需求。
  18. 代码用Maven,Gradle等进行build
  19. 拼接SQL语句需要考虑的SQL安全性,SQL 的 保留关键字或字符,建议用PreparedStatement去完成。

Log

  1. 清晰的日志易于做troubleshooting
  2. 清晰的日志易于team之间的交流和学习。
  3. 日志注意拼写错误,英文合适。
  4. 日志需要将业务分步描述清楚。
  5. 建议developers多做Ops的工作,以便于了解到底什么样的日志才是优美的。
  6. 对于正常的业务也许打log,对于异常的case务必打log。常遇见的情况是正常的业务逻辑少,只有一些exception的case 才打。导致正常业务出问题没法进行troubleshooting。
  7. log的级别。什么样的信息适合什么样的log level,取决于业务。

SCM(SVN/GIT)

  1. 保证仓库里的代码是可以编译通过的。
  2. 代码尽量每天提交。
  3. 一次只提交一个功能或者bug fix代码。
  4. 提交代码时,写上comment描述当次修改。
  5. 如果是bug fix,在comment里注明bug id,如果是功能,注明requirement id。
  6. 安装合适的工具,例如Trac, Phabricator,以及Bitbucket等

Code Review

  1. 强烈建议team之间内部相互review。
  2. 条件允许的话,只有代码进行code review过了,才可以commit到仓库里。
  3. 开Code Review会议前,相关人员提前review一遍。在会议上只提问。
  4. Code Review时只提及修改的部分。
  5. Code Review可以用一些工具,例如Phabricator,ReviewBoard,以及Bitbucket等。

Test

  1. 写单元测试(Unit Test), 可以简单理解白盒测试。
  2. 写功能测试(Functional Test),可以简单黑盒测试。
  3. 一般项目都会用daily build,将单元测试和功能测试加入daily build的task中。
  4. 代码覆盖率也很重要。
  5. 代码必须测试过才可以发出去(内部或者外部)
  6. Test Cases需要详尽才可以,认真写。
  7. Test Cases不是应付,不是交代,而是软件质量的一小步。
  8. 用测试框架去Test case,。例如,在Java里,很多人有个习惯是在class里增加一个main方法去驱动测试某个函数。

 

修改历史记录

  1. 2017-03-08, 第一版起稿。
  2. 2017-03-09, 增加测试部分,以及部分coding规则。
  3. 2017-3-13,增加设计章节。增加测试部分(>=6),log部分(>=6),代码部分(>=14)等
  4. 2017-3-16,增加设计部分(>10)
  5. 2017-4-21, 增加coding 的18,19,修改Log的6

11/19/2009

文档

Filed under: 一技之长 — 张太国 @ 15:54

在工作中,一份好的文档对于project起到非常积极的作用,过多的益处我就不再赘述,很多书籍已经说明。

但是,一份质量差的文档呢?恐怕会适得其反。

很多时候,每个项目都有固定的流程,所以写文档就是为了走流程这样一个目的。无论你文档写的再好,也是没有人看的。写的好也就罢了,但是写的不好呢?我想是没有人看的,这样的情况下不写也罢。

很多时候,每个公司都有自己的文档规范。所以新员工不知道是怎么回事情,如果不培训的话,不要期望在短时间内写出好的文档。但是这样的公司还是挺多的。这样的情况下,不写也罢。

很多时候,即使你知道文档格式,但是文档内容有时也不太清楚,所以也不要太指望写出好的文档,只有在自己熟悉的基础上才能写出好文档。如果你不能清楚知道内容,这种情况下,不写也罢。

我倒不是反对写文档,相反,我是非常支持的。但是如何写出好文档,至少需要以下几个方面:
1. 良好的文档格式
2. 良好的写作能力
3. 良好的掌握所写内容
4. 良好的培训
5. 良好的公司氛围来写文档

我写这些,知道意味着什么吗?

02/04/2009

Hello, Memory Leak

Filed under: 一技之长 — 张太国 @ 17:52

已经有3年没有认认真真写过C/C++程序。即使是写,也是写些小程序。

因为项目的需要,与C/C++再续前缘。令人崩溃的是,我写的程序居然出现内存泄漏,直接吐血。以前,也有一次出现过内存泄漏问题,记得当时写的是一个monitor工具,一直运行在机器上,有意思的是每次执行泄漏4个字节。原因后来找到了,都是CString惹的祸啊。

这次的情况和上次不一样,没那么简单,一直用到其他库,二是因为自己对这门语言开始生疏了,造成了很大的问题。今天一口气将其解决掉,经验分享如下。

如何知道内存泄漏?

我是用VS.NET 2003开发的,该工具挺好的,当我调试时然后关闭应用程序,在output窗口就会显示,例如,

Detected memory leaks!
Dumping objects ->
{10381} normal block at 0x01C76F40, 4 bytes long.
Data: <  t > EC 9C 74 00
{9443} normal block at 0x01C37D68, 4 bytes long.
Data: <  t > EC 9C 74 00
Object dump complete.

说实话,上面提示只能告诉你内存泄漏存在,而且泄漏多少,但是没有告诉你在哪里泄漏。还好,一个开源的小工具能够帮助我们定位到具体位置。这个工具就是Visual Leak Detector , 至于如何使用,网上文章特多,在这里我还是简要说明一下。

  1. 将include文件放在系统的include下,如果使用VS,那就放在VS的include下。
  2. 将lib文件放系统的lib下,如果使用VS,就放在VS的lib下。
  3. 在需要的源文件引用一下就可以了,例如#include<vld.h>
  4. 将dll放在执行文件的目录那里。

debug应用程序,然后关闭,在output下会出现:

No memory leaks detected.
‘xxx.exe’: Unloaded  c:\xxxx\Debug\dbghelp.dll’
Visual Leak Detector is now exiting.

上面是最简单的方法有个缺点,要是我不想讲include等文件放在系统目录下,而想将其跟我的工程一起放怎么办?很简单,将include,lib等文件拷到自己的project下,如果使用VS,请在设置里将include,lib将这些目录加上,然后再lib的那里加上vld.lib即可。不同的IDE不一样,也许不用加上。

当然还有很多更好的工具,不过VLD已经够用了。

如何避免?

避免内存泄漏的方法还是在于防范。

我觉得最根本的原理就是请求内存,然后释放内存。往往我们就是只请求不释放。

原则可以如下:

  1. new一个,一定要delete
  2. malloc一个,一定要free
  3. 有时候并没有new/malloc,但是还是请求了资源,这个时候也要free。
  4. 不要返回一个对象或者一个对象的指针,代替的是在参数里进行传址。
  5. 如果你非得返回一个对象或指针,那引用该函数的人一定有义务要删除。

1、2不多说了,太简单,举个很有意思的例子。CString我们都熟悉,但是用好还真不容易,new了一个一定要删除,有时候会调用GetBuffer,事后是否需要ReleaseBuffer呢?

说第3点。先举个例子:

char* val = XMLString::transcode(subNode->getFirstChild()->getNodeValue());
//do your thing here
  XMLString::release(&val);

上面val其实分配了内存,所以要在下面释放,XML::release就是干这个事情的。也许我这么说很明白,按时真到了关键时刻,可能就忘了,也许有这样的写法:

std::string msg(XMLString::transcode(subNode->getFirstChild()->getNodeValue()));

说不定我们写完了以为就没事了,但是事情往往就出现在这里。

第4点,很多人都会犯,包括我自己。

先看这样如下代码:

Class A
{
  public:
  A();
  ~A()
}
class B
{
public:
B();
~B();

A f1(){return new A();};
A* f2(){A* a = new A(); return a;};
}
B b;
A a1 = b.f1()
A* a2 = b.f2();

上面的代码就是模拟第4点写的。第一看没问题,这在C#,Java里,这种思路在普遍不过了,但是在C/C++这里需要注意,返回一个临时对象是不安全的,即使访问指针,也是不安全的。如果要变的安全,需要费劲,而且你必须遵照第5点,手动删除它。

什么是安全的使用方法?我们可以改写一下:

Class A
{
  public:
  A();
  ~A()
}
class B
{
public:
B();
~B();

int f1(A* a);
}
B b;
A* a1 =new A();
b.f2(a1);

这样做就安全许多。因为f1将指会存入a1指向的地址那里。

其他

为了避免内存泄漏,有个比较好的方法就是RAII(Resource Acquisition Is Initialization),一般用在类里,思想就是在析构函数里将资源释放掉,即使在使用的过程中忘了删除,最后对象销毁时也会释放的。举个例子:

#include  
#include  
class file 
{ 
public: 
    file (const char* filename) 
        : file_(std::fopen(filename, "w+")) 
    { 
        if (!file_) 
            throw std::runtime_error("file open failure"); 
    } 
    ~file() 
    { 
        if (0 != std::fclose(file_)) // failed to flush latest changes? 
        { 
            // handle it 
        } 
    } 
    void write (const char* str) 
    { 
        if (EOF == std::fputs(str, file_)) 
            throw std::runtime_error("file write failure"); 
    } 
private: 
    std::FILE* file_; 
    // prevent copying and assignment; not implemented 
    file (const file &); 
    file & operator= (const file &); 
};

上面~file()里,也会把file_干掉的,即使字啊write里没有释放。

程序员是很懒的,所以有时候不会主动释放掉,更不用说粗心大意的人了,即使是谨慎的人,也不会时时刻刻去关注。即使是,后期维护人员难道知道处处到要释放吗?不能保证啊。

上面是方法之一,接下来就是只能指针,auto_ptr,当这个指针销毁时,其对象也销毁。看看下面的代码:

using namespace std;

class MyClass {

public:

  MyClass() {} // nothing

  ~MyClass() {} // nothing

  void myFunc() {} // nothing

};

int main() {

  auto_ptr<MyClass> ptr1(new MyClass), ptr2;

  ptr2 = ptr1;

  ptr2->myFunc();

  MyClass* ptr = ptr2.get();

  ptr->myFunc();

  return 0;

}

如果ptr1销毁后,那么在new MyClass()也会销毁。

关于智能指针我不多说了,毕竟我也不是特别精通啊。

暂时就写这么多,以后在更新吧。

10/20/2008

基础还是真重要的

Filed under: 一技之长 — Tags: — 张太国 @ 16:08

一些知识太久不用,发现自己都快遗忘了。上周和某位同学一起聊天,谈到了一些最基本的知识,因为自己的生疏,或者不懂,搞得自己有些尴尬。为了改变这一现状,还是先熟悉一下例我远去的基础知识吧。

今年来自己状态也不是特别好,总被这样那样的事情分心,所以也没有时间去整理一下。事实上,与其说这样的理由,还不如说自己因为一些事情导致自己心都懒惰了,所以这些知识才离我远去,突然想起刚毕业那会和一年前那种干劲,真的很怀恋。

话不多说,是时候捡起来了。马上行动,先写一个计划吧。

Older Posts »

Powered by WordPress