SUMTEC -- There's a thing in my bloglet.

But it's not only one. It's many. It's the same as other things but it exactly likes nothing else...

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  264 随笔 :: 19 文章 :: 2999 评论 :: 22 引用

公告

置顶随笔 #

摘要: 我说了决定了,是不会随便更改的。尽管这里看的人很多,但是我有我的考虑,基本上该讲的已经讲完了。有人说,“你不是走了么?怎么又回来发一篇文章?”我怀疑我这么发文章,那些这么怀疑我的人是否会看到。一句话解释:有人问我会去哪里,我在这里留一个路标,你以后也不会看到我在这里的任何新增加的文章,也不会看到任何的回复。This is it.我去哪里还没有定,试了几个地方觉得不是特别顺手,目前最终决定还是暂时先放在新浪。如果:1、以后有别的变动,我承诺一定可以在新浪博客看到后续的路标,你沿着找应该能找到;2、不幸被新浪关了,那我也会很负责任的在本篇博客中进行修改和补充;3、你有任何疑问,请移驾最新的博客位置阅读全文
posted @ 2011-09-02 09:19 Sumtec 阅读(258) 评论(0) 编辑

2011年9月2日 #

我说了决定了,是不会随便更改的。尽管这里看的人很多,但是我有我的考虑,基本上该讲的已经讲完了。

 

有人说,“你不是走了么?怎么又回来发一篇文章?”我怀疑我这么发文章,那些这么怀疑我的人是否会看到。一句话解释:有人问我会去哪里,我在这里留一个路标,你以后也不会看到我在这里的任何新增加的文章,也不会看到任何的回复。This is it.

 

我去哪里还没有定,试了几个地方觉得不是特别顺手,目前最终决定还是暂时先放在新浪。如果:

1、以后有别的变动,我承诺一定可以在新浪博客看到后续的路标,你沿着找应该能找到;

2、不幸被新浪关了,那我也会很负责任的在本篇博客中进行修改和补充;

3、你有任何疑问,请移驾最新的博客位置,或者可以在新浪微博上找我,此处不做任何回复评论,包括以前的任何文章;

4、你有比新浪更好的博客Hosting推荐,请推荐之,我会尝试使用和考虑的。

 

我的:

新浪博客:http://blog.sina.com.cn/sumtec

新浪微博:http://weibo.com/sumtec


感谢过去各位的围观,就算以后不围观,我也鞠个躬。 

-- END -- 

UPDATE:

新浪的微博进入低活跃度状态,尚可联系;新浪博客进入休止状态,转用blogspot。各种联系方式如下:

非死不可:https://www.facebook.com/sumtecChina

推特:@sumtec_china

G+:搜索sumtec

博客:sumtec.blogspot.com 

 

以上联系方式需要翻墙,翻墙请参考我新浪微博中最后的蛛丝马迹。 

posted @ 2011-09-02 09:19 Sumtec 阅读(258) 评论(0) 编辑

2011年8月19日 #

博主您好! 
首页是发表精品文章的地方。 
您的博文“QUIZ:一个有8个属性的匿名类大约会占多大的文件大小?”被移出首页,由此给您带来的麻烦,请谅解! 
首页文章要求:原创,排版整齐,文中有文字明确说明文章的主题,内容对程序员有帮助。 
下列类型的文章不允许发到首页: 

1) 转载;2) 只有代码;3) 简单的提问;4) 软件发布;5)人才招聘;6) 包含推广或广告内容;7)活动信息;8)关闭评论功能的随笔;9)不完整的内容。

 

既然抛砖引玉中的抛砖不能出现在首页,那我也不想引玉了。真遗憾,在博客园中用了这么长的时间,我终于有了当年从CSDN退出时的感觉:实在无法理喻这里的风气了。难道C#自己写的一个自定义分页控件就是一个很有价值的文章?我的意思并非这样的文章就不好,而是说,一个引起思考的短文居然和这个比都没有价值,我不知道这样的地方价值在哪里?或者说,这样的地方已经没有多少营养了,需要认真考虑另起炉灶了。

 

我想问一下,认为不值得放首页的那些个同学,你们有几个能回答出我说的这个问题?你们有几个自己真的做过这方面的研究?知道MetaData都包含什么?这个是一个简单的提问?

 

前阵子微博上还有人调侃,说:

 

其实我倒不是觉得不能写一些非技术的东西,或者制造一些话题。但是,现在真不是观众说了算,一些我觉得没啥看头的东西占据了首页,一些其实蛮有看头的东西却被大量水文瞬间冲掉。好,废话不多说,最后给出这个被强制移出首页的QUIZ的答案。

 

一个包含了8个属性的匿名类,会占用大约5K的文件存储空间。也就是说,如果你使用了10个这样的匿名类,你的文件大小就会导致你的文件增大大约50KB。对于一个桌面应用来说,50KB算不上什么,但对于一个SilverLight应用来说,这就不是一个小数目了。更可怕的是,如果我们不知道这个问题,使用了一个比如说42个属性的匿名类,就会导致你的文件增长大约46KB的大小。当然,这里有严重的水分,原因后面会简单提到。


在开始进行一些简单的分析之前,也许你需要自己去了解一些有关CLI的知识,比如什么是BlobHeap、UserStringHeap、StringHeap、TableHeap等,以及里面是用什么格式进行组装的。原本呢,我觉得这些大家只要用Google搜索一下CLI和MetaData就会出来了,可是我现在觉得,以博客园的平均水平而言,也许连这个能力都不具备。那么好吧,下面这个是链接,有能力的请自行阅读:

http://download.microsoft.com/download/d/c/1/dc1b219f-3b11-4a05-9da3-2d0f98b20917/partition%20ii%20metadata.doc

 

下面,我们来对这一个问题进行一下简单的剖析。为了让问题更明显和突出,我们对一个有42个属性的类进行分析。

 

首先,整个匿名类哪些部分会占用的比较多? 根据统计,在TableHeap中使用了5k,StringHeap中使用了7k,Blob使用了27k,UserString使用了1k,Body占用了近5k。需要说明的是,除了Body部分(IL代码)相对比较准确之外,其它的部分的统计是不准确的。这是因为根据规范,相同的内容很可能会自行排重而只记录一遍。而同一个内容在整个程序集中会多次被使用到,据一个例子:比如属性的访问器名称get_PageId,可能在多个类当中都有该属性;此外还有其它很多原因可能会导致重复统计。根据我的估算,可能需要打个3折,即便如此也得占用大约14k的空间。为了便于讨论,我们这里就先忽略这些重复的统计。


途中的Blog占用空间非常大,至于为什么,这是我尚未解开的部分。也许是因为:

1、BlobHeap包含了太多的东西,比如一个函数的签名,标签(Attribute)所使用的具体参数等;

2、使用的场景也比较多,比如TableHeap中的MethodRef、Method、Param等等,几乎各个Table都可能有指针指向Blob。甚至连MethodBody当中的某一句IL,比如call System.Linq.Quearyable.Where'1 ... 等,都可能会在Blob里面加一些东西;

3、从Reflector看到的情况无法解释这一部分异常增大的原因,甚至不排除这个工具本身哪里有Bug导致统计数据出现了错误。

但无论如何,也不是重复统计所能解释的,关于这部分后面会给出两个图进行说明。


抛开奇怪的Blob部分,还有一些很容易发现的问题。比如,为什么一个匿名类需要使用1k的UserStringHeap呢?UserStringHeap中记录的是你代码当中的字符串常量,比如说下面这么一段代码:

void Main()
{
  Console.WriteLine(
"Hello world!");

 

这么一个语句,当中的"Hello word!"就是要进入UserStringHeap的,大约会占用23个字节。可是我们的匿名类里面,怎么会有字符串常量呢?原来,编译器在生成匿名类的时候,为了便于你调试,会在类的前面打上一个DebuggerDisplayAttribute标签,比如:(为避免泄露些什么,字段名称已经修改,字符串中的...表示后面还有好长好长……)

 

DebuggerDisplay(@"\{ PageId = {PageId}, ReadId = {ReadId}, RefId = {RefId}, Guid = {Guid}, TypeId = {TypeId}, CategoryId = {CategoryId}, Title = {Title}, Mode = {Mode}, Setting = {Setting}, Tags = {Tags} ... }", Type="<Anonymous Type>")]

 

 

打上这一个标签的好处是,当你进行断点调试的时候,你可以看看这个匿名类里面的属性值都是什么。可正是这个标签,导致了UserString的占用。由于不同匿名类中,属性名称可能会不一样,就算一样,顺序也可能不一样,因此这串字符串也就不太可能完全相同。于是,你用的匿名类越多,这种无谓的占用就会越多。幸好,这个问题只会出现在Debug的编译结果中,对于Release发布则没有这个标签。

 

接下来,也许你会奇怪,对于一个42个属性的匿名类,所使用的StringHeap会达到7k,好吧,这是我的工具重复统计导致了过分的放大。但是,仔细看一下匿名类你就会发现:

1、一个有着N个属性的匿名类实际上是一个有N个泛型参数的泛型类。假设有一个属性是PageId,则:

2、属性名称叫做PageId;(7个字节,注:C字符串格式最后有一个字符0)

3、属性的访问器叫做get_PageId;(11个字节)

4、属性所对应的成员叫做<PageId>i__Field;(17个字节)

5、属性的泛型参数名称叫做<PageId>j__TPar;(16个字节)

6、匿名类名称为AnonymousType#`N,数字#表示第#个匿名类,数字N表示有N个属性。那么对于有着8个属性的匿名类1,长度就是17个字节,对于有着42个属性的匿名类2,长度就是18个字节;

7、假设我们属性名称的平均长度就正好是6个,那么42个属性的匿名类就至少占据了2k有多。

 

从上面这个部分,我们就可以发现,假如我们把几乎不会影响一般运行,甚至对反射也没有太大影响的成员名和泛型参数名优化一下,变成平均4个字节(甚至是0字节),那么也可以减少超过一半以上的空间占用。对于使用匿名类较多的某个dll来说,光是这部分可能就可以优化掉大约10k左右的大小。

 

另一个让人吃惊的地方,是MethodBody占用非常大,大5k之多,平均一个属性有大约100多个字节。要知道,一个如下的属性:

public int PageId
{
  
get
  {
     
return _pageId;
  }

对应的il也就如下三句:

ldarg.0
ldfld thisType._pageId;
ret

 

 共6个字节。如果是Debug编译,会多出额外3句以便于调试,也就在多4个字节而已。换而言之,有其它的函数在哪里捣鬼,捣鬼的那几个函数分别是:

Equals、GetHashCode、ToString以及构造函数.ctor。

 

 

如果我们用Reflector打开这个函数来看,Equals、GetHashCode、ToString以及构造函数都要访问到每一个属性。其中对于构造函数来说,这是几乎不可避免的,因为需要对匿名类的每一个属性进行赋值操作。但是为啥需要重写Equals等其他三个函数呢?这是因为这些对象可能会被用到Dictionary的Key中,此时就必须重写Equals、GetHashCode、ToString这三个函数,而这三个函数加起来就得占用大约4k的大小。准确说,所有匿名类的属性总数,决定了整个dll中该部分代码的大小。如果你这个dll中一共有10个匿名类,每个大约10个属性,那么光是代码部分,这三个函数就占用了大约10k的大小。不要忘了,除了代码之外,我们还需要因此写入一些元数据,以及为数不少的UserString。而实际上用到这三个函数的几率非常非常的小,完全可以通过实时动态Emit来完成,而不需要占用这么大的代码空间。当然了,进行动态生成的代码也会占用不少的空间,但如果你做的是一个很大的项目,比如你有很多的页面,每个页面用到不同的Dll,里面都有不少的匿名类,那么这点的优化成本很可能是值得的。而另一种方式也许更好,那就是假设该类不会被当作对比的Key来使用,而是当作一个普通的类,那你可以干脆裁减掉这三个方法(这种裁剪我还没有试验过,也许你需要自己进行尝试)。

 

最后,我们来看看Blob方面的一个奇怪的问题,那就是:匿名类的属性越多,则某一个属性需要用到的Blob就越大。比如说对于一个有42个属性的匿名类,其某个属性访问器所使用用到的Blob大小如下图所示:(包括方法签名,方法中调用某函数、使用某成员所产生的一个MemberRef记录所用到的方法签名等)

 

而一个只有8个属性的匿名类,其某个属性访问器所使用到的blob大小为:

 

目前我想到的合理解释是,由于需要返回该属性对应的字段,如下述IL代码:

ldfld !0 <>f_AnonymousType0'42<!<xxx>j_TPar, !<xxx>j_TPar, ...>::<PageId>i__Field 

这里需要产生一个针对该字段<PageId>i__Field的签名,而签名当中又带有当前类的各种泛型参数信息,因此造成了属性越多,占用Blob越厉害的结果。而至于这部分的Blob是否如我猜测,如是,是否会每个参数都要占用这么多还是其中一部分会被重复利用,都尚未可知。当然,也有可能我的程序有Bug造成的。关于此,我想我不会在博客园继续写了。

 

如果有兴趣的同学,可以去下载一个开源的项目,叫做Mono.Cecil,我的工具就是在这个项目的基础上去完成的。通过该项目的源代码,你可以很好的了解整个.NET文件的结构组成。当然,在你正式开始阅读这部分代码之前,最好先看看我前面提到的那篇文章,因为这个Mono.Cecil的项目里面,注释量基本是Zero。对于那些从来不喜欢Read the fuck code的同学,会是一种巨大的挑战。

 

最后,我宣布从博客园正式退役了,不玩了。有些东西抱怨太多就没意思了,每次发布都要头痛,到底是放首页呢还是放首页呢,还是放首页呢?然后要从一堆花花绿绿的各种我都不知从何下手的选项中,选一些我知道的不知道的东西,简直就是一场噩梦。

 

关键是,没错,我很不爽,你们把我觉得还比较有难度有挑战的小提问给挪出去了,你们不提倡思考了,开始喜欢浮躁喜欢造话题。那些相对来说没啥技术含量的东西,字数也不见得多出多少,不也照样放在首页吗?既然咱们的人生观价值观已然发生分歧了,那只好分道扬镳了。

 

我刚刚做了一个非常艰难的决定,那就是博客园,我不玩了。至于你们信不信,我反正是信了。走咯,回家了,拜拜了各位!

 

 

 

posted @ 2011-08-19 19:25 Sumtec 阅读(4279) 评论(107) 编辑

答案:It depends.

 

“你去屎吧!”

我猜一定会有人这么说。既然“

改天我也去发一篇“QUIZ: 园子一个用户发多少篇给个问题还看心情才给答案的文章才会让全园友崩溃,是什么原因”放首页来好了 ”这样的回复,上面那个想法也肯定必然的。好,那我先剧透一点:这个崩溃和里面的那一个字是什么有关,而且和你是什么职业也有关。

 

“靠,这怎么可能,你干脆说是人品问题好了!”好吧,如果你真这么想,那我也只好说,至于你信不信,我反正是信了。


其实我发这些个QUIZ的原因,是发现了一些有意思的问题,希望大家去实验一把。可是现在园子水平真的很不济,貌似愿意动手刨根究底的人并不多。这也是我在工作中发现的一种现象,很多人都“知其然不知其所以然”,并且心安理得。好吧,抱怨到此结束,下面来说说这个很奇妙的崩溃问题。

 

在我们的工作当中,发现了一个很奇怪的崩溃现象:(非常抱歉,没有任何截图,描述的也不是很清晰,因为这不是我的工作,也就没有第一手资料。)

1、某些人的机器永远会崩溃,无论是用什么浏览器都一样;而另一些人的机器则无论如何都复现不出来;

2、对于会崩溃的机器来说,则在某些个页面上打一开始就崩溃。尤其是IE7,会直接弹出一个红叉对话框,里面一串十六进制数字,显示类似Access denied之类的类似C++错误提示的东西。.NET不是应该托管安全的么,怎么会这样呢?

3、对于崩溃之前的那一瞬间,既没有看到占用内存大小有什么特别不正常,也没有看到CPU负荷有什么不正常。 


对于上面的这个疑惑,我们甚至做了个Dump,开始的时候以为是IE7里面的某个COM组件的错误,因为用WinDbg看出错时堆栈位于当IE窗口大小发生变化之后所经过的代码。可后来的发现证明完全不是这么一回事,因为有人做了一个实验,发现出现崩溃和同一个页面上有多少个SilverLight应用有关。前面这个条件是必要但非充分的,因为在同一台机器上,有的页面不崩溃,有的页面就会崩溃。差异就在于有前者只有1个SilverLight应用,而后者则同时加载并显示了4个应用。

 

可这解释不了为什么有的机器会崩溃,有的则不会。对于这个问题,我们做了不少的假设,比如说:系统内存大小,操作系统版本,浏览器版本,内存泄漏,没有正确的处理异常,各种线程安全问题,SilverLight核心版本不一致,开发版和普通用户版,等等,乃至中毒。随着前面那几个比较严肃的怀疑被一一排除,我们甚至笑谈到了人品的问题。因为开发的时候我们从来没有遇到过这个问题,只是在内部使用的时候,个别美工和设计师会出现这种尴尬的情况,而且没有一个开发人员能用他自己的开发环境复现这个问题。甚至还有人下载了Silverlight 5 Beta来试,发现临界值从4个变成了5个。这个结果让人哭笑不得:有变化了,但解释不了什么问题。

  

就在我们一筹莫展的时候,这位同事又做了一个简化实验:同时展示4个完全相同的SilverLight,里面就一个TextBlock,随便写了几个字。就这么简单的一个应用,如果一个页面显示4个,则会发生崩溃的机器仍然会发生崩溃。这时候我们就开始怀疑,这个问题真的跟我们写的代码,乃至.NET Framework中的托管部分没有任何关系了。进一步的实验发现,只要输入中文,或者使用了中文字体,就会崩溃。只要TextBlock中的是一个英文,并且没有指定字体,或者指定的字体是英文的,就不会崩溃。

 

现在问题指向就比较明显了:中文,或者中文字体就是元凶。到了这里,我们恍然大悟,怪不得会发生崩溃的机器,全都是美工和设计师的。这些美工和设计师因为工作需要,会安装各种你所见过或者从未见过的字体。这时候我们还非常惊讶的发现:

1、我们的Demo里面并没有使用任何特殊安装的字体;

2、即便我们把我们需要的字体打包到XAP里面,仍然不管用;

3、即便我们显示的是英文,但只要指定任意一种中文字体,也会崩溃;

4、对于安装了字体的用户,如果把注册表改了(也就是假装这些字体并未安装),崩溃的症状也就消失了。 

 

这时候我们发现,要解决这个问题,似乎就只能够告知用户,把某些有问题的字体给删掉,或者给他们一个禁用某类字体的脚本。但到底是哪一个,或者哪一些字体会出现问题呢?同事再次陷入了困境,因为实验表明:

1、某一些字体一定不会出问题,我们称为A组;

2、另一些字体则同时存在时,一定会出问题,我们成为B组;

3、将B组字体每三个分成1个小组,随便禁用任意1小组,就不会崩溃;

4、B组字体非常多,逐个实验很耗时间,但随即抽了几个发现,似乎禁用任意1个,也不会崩溃。

 

正当大家都在讨论,这时一个什么问题的时候。当当当当!我闪亮登场了,我说:那看起来不是某个字体有什么畸形的东西在里面导致了某种原因不明的错误,很可能是因为中文字体大小和英文字体大小的原因。尽管很奇怪,比如说崩溃之前内存也没有达到接近2G大小,不应该是OOM这种问题,而且我从来没有、将来也不会用到的字体,为啥要一股脑儿全部加载进来呢?但也不是不可能的事情,毕竟中文字体和英文字体确实有这个差异。在这个思路下面,我们做了这么两个实验:

 

实验一:在会发生崩溃的机器上面,把B组字体删除1个,使得同事显示4个应用不会发生崩溃,然后再加载第5个应用。结果毫不意外,崩溃了。

实验二:在之前我们认为不会崩溃的机器上面,加载N个应用,发现在大约加载到30个的时候,也发生崩溃了。注意,不是.NET报告的OOM异常,我们不可能靠自己写代码能解决此问题。


目前,我们的进展只到了这里,进一步的排查和问题的机掘可能会非常困难,因为已经远超托管范围内的世界了。这个问题最好是微软来解决,因为严格来说这时一个Bug。但是至少,这个QUIZ的答案有了:

 

如果包含中文,或者指定了任意一个中文字体,则一个页面包含1到30个左右的SilverLight应用就可能会导致莫名其妙的无法启动的崩溃。具体是多少还取决于你的职业,比如你是一个很无趣的程序员,这个数字可能是30甚至更大;但如果你是个天才美工,爱好装各种各样牛逼的中文字体,那么这个数字也许是1;而如果你在程序员和美工之间,这个数字就不定了,最常见的数字可能是3到5。哦,对了,还可能和SilverLight版本有关,比如说SL4的数字是4,那么SL5的数字就可能是5。

 

嗯,还有一个QUIZ,答案也敬请期待。 

 

posted @ 2011-08-19 15:54 Sumtec 阅读(1992) 评论(17) 编辑

一个很简单的SilverLight4应用,上面只有一个TextBlock,里面只有一个字。你猜,这一个SilverLight在同一个页面中创建多少个时,会出现莫名其妙的崩溃?这种崩溃和什么有关?

 

哈,知道的同学不要说话。同样,这个问题的答案也是要看我心情如何,心情好的时候就会上来写,嗯。

 

P.S.: @dudu

What is the god damned order of your priority in developing this website? Making money, or making it easy using for us? Why the sooooooo complex publishing panel still there after I complaint it almost one year?

posted @ 2011-08-19 10:03 Sumtec 阅读(537) 评论(2) 编辑

2011年8月18日 #

在你们的开发当中,是否用过匿名类?也就是比如说:

var query = from item in database.Pages

 where item.PageId == 100 

                 select new {

                      item.Id,

                      item.Title,

                      item.CategoryId,

                      item.Tags,

                      item.ReplyCount,

                      item.ReadCount, 

                      item.RecommendCount, 

                      item.Abstract

                 }; 

 

其实就是一个再普通不过的匿名类,每个属性的名称也不是特别的长,你猜因为使用了这一个匿名类,会导致文件大小增长多少呢?增长的这部分大小主要是因为MetaData呢,还是MethodBody呢?如果是MetaData的话,那是因为类的各种属性名、方法名等造成的呢,还是一些用户常量数据造成的呢,还是别的什么?

 

还是和之前一样,等我高兴了我就把答案贴出来。(其实是有一个问题还没有搞清楚,哈哈,你们等着吧。) 

posted @ 2011-08-18 14:13 Sumtec 阅读(1312) 评论(7) 编辑

2011年8月11日 #

答案是:System.Security.Cryptography (.NET FX 4.0,见下图)

 

这个Quiz看过的人不超过160个,说明大家越来越水了。打口水仗各个精神百倍,唾沫星子四处飞。真正来实际的,就全都瞎火了。还记得很久之前某人的一个说.NET咋咋不好的一个系列贴吗,其中有一集说Metadata很大又没有用应该去掉等。当时这个帖子多么火热啊!可惜是否真这样,谁又真的研究过呢?要挑事一定要拿出证据来,批驳别人也一样的。当时我对此兴趣缺缺,只想说这不是什么重要的问题,大家洗洗睡吧,所以也就没多深挖。后来因为有SL4的项目,需要对XAP包瘦身,于是就顺道研究了一下.NET的DLL空间大小都分布在什么样的地方。正因如此,就自己写了一个小工具,可以看到底是什么占空间。

 

比如拿mscorlib为例吧,整个文件中大约60%的空间是IL代码,剩余的40%是MetaData,这其中的60%(也就是整个文件的约24%)由TableHeap占用。而TableHeap当中,MethodTable占了36%(整个文件的8.64%),ParamTable占了21%(整个文件的5%),CustomAttributeTable占了12%(2.88%),FieldTable占10%(2.4%)……(见下图)

 

 

等会儿,什么是MetaData?那些个什么Heap又是什么,Table又是什么?图中那个.text什么的又是啥?好,我们从大往小讲,先说说.text。

 

Windows的可执行文件会根据所承载的内容放在不同的段里面,比如.text就是放代码的段,可读可执行不可写;其实一般的应用有可能还有另一个.data的数据段,不可执行可读写。对于.NET的可执行文件(包括dll)来说,只有.text段,所有你的代码资源什么的通通被打包到这个段里面。好,这部分就解释到此,更细节的就于此无关了。

 

接下来,我们说说堆。.NET文件的堆包括以下几个:

BlobHeap,用于保存各种大小类型不一的元数据,比如方法的签名信息等;

GuidHeap,用于保存各种程序级别的GUID,一般来讲你可以忽视它;

StringHeap,用于保存程序本身的字符串,例如命名空间名、函数名、类名等等,这个部分是UTF-8的C编码字符串,也就是以0结尾的;

TableHeap,用于保存各种数据长度固定的表,后面再详细解释;

UserStringHeap,用于保存程序中的各种字符串常量,比如:

string s = "你好"; // 这个“你好”就会被保存在这个堆当中。这个堆和StringHeap的区别是,他使用UTF-16来保存的,并且是.NET格式编码,即,前面一个7BitEncoded的表示长度的数值,后面跟着字符串。

 

现在,我们不清楚的就该剩下TableHeap了,这里我不做详细的解释了,只拿一个MethodTable来说明问题。MethodTable会记录该方法的名称指针(指向StringHeap),方法的签名指针(也就是这个方法有多少个参数,分别是什么类型等等,指向BlobHeap),方法参数的描述指针(比如每一个参数是否和COM的什么描述有关,或者参数名是什么等等,指向ParamTable),方法的其它各种常规属性比如调用制式,以及一个指向Body的指针等。当然了,我们可以想象,还会描述这里面有哪些类的TypeDefTable,这个类里面都有什么属性的PropertyTable,有哪些字段的FieldTable……

 

如果你在这个的基础之上再去看看IL的格式,就会发现IL里面对函数的调用等,都不是直接给出一个地址,而是一个MetaData中的记录编号(第几个方法)。即便我们不需要反射,我们也不可能完全去掉MetaData而只能简化一小部分。比如说Param这个表里面的内容就几乎不是必须的,比如说如果你不没有在某个参数上打标签(Attribute),也与COM无关,并且也不期望通过反射来进行参数的查找,那这个函数就可以不产生Param表的一项。至于说方法的签名,你可以说其实不是必须的,但是这个和托管的概念是很有关联的——缺乏这个信息,核心就不能校验你的调用是否给出了正确的参数。在DLL的小版本改进中,随时可能会出现参数多了少了的问题。而是用该Dll的代码在调用的时候,就可能会出现各种莫名其妙的错误,甚至是不容易察觉的错误。

 

这么仔细想一下,Meta想要瘦身也不是一个容易的事情——要么损失托管的好处,要么优化不了多少。你看看上面的数据,每一项占整个文件的大小都不大,除非你整个的去掉。

 

当然了,如果你希望能优化点是一点儿,那么我可以给你几个提示:

1、以下的优化你必须自己写工具来处理,你可以利用一个开源的Cecil库来自己裁剪。当然了,某些混淆器也提供这样的功能,但是效果如何没研究过,而且很多时候貌似是以输出一个更大的文件为结果的; 

2、目前的StringHeap输出其实很傻,Enabled属性的getter叫做get_Enabled,是会被输出成两个字符串。但实际上C编码字符串的好处是,你可以指向一个字符串的中间。也就是说,你可以指输出get_Enabled,然后Enabled指向get_之后一个字节;

3、其实一般情况下,私有成员是不希望被使用的,如果你认为无反射需要,其实可以将这部分的成员名称随机指向一个已存在的StringHeap字符串。当然,如果你认为某个类有需要被反射调用使用,那么你可以给该类打上一个特定的标签(Attribute),你的工具则识别并跳过它;

4、ParamTable中大多数项可以裁剪掉,那里面大多数就记一下这个函数中各个参数的名称叫什么,如果你不需要反射并查找参数名称来进行各种匹配,貌似是可以不输出的;

5、不要试图重复利用ParamTable中已存在的项,这样做是徒劳的,因为实际上核心是按照顺序读取的——它加载文件的时候,会有一个指针指向当前使用的Param项,然后根据MethodTable中记录的ParamTable项数来读取若干条记录。总之,别浪费时间尝试用2当中的思路;

6、一个文件中的类、方法、属性等,最好不要超过65535个,一旦超过了,对这些内容的记录就会从2个字节增长为4个字节;

7、减少程序中的字符串常量,比如说,你可以利用反射来读取类和方法的名称时,就不要写一个“Type”这样的字符串,又或者自己用合适的编码比如UTF-8来编码一个文件并进行加载等。

 

通过使用上述方法,你有可能可以节约大概10%-50%的空间,文件越大效果越不明显。因为当中会有大量的IL代码,这部分你是很难进行优化的,至少你需要改动代码甚至结构。

 

P.S.:

1、各种资料请自己动手搜索吧,比如搜搜CLI或者UserStringHeap之类的; 

2、那个查看大小的程序,实在对不起,基于某种原因我不可能给大家提供。但是其实你下载一个Cecil的代码,改吧改吧还是很容易实现的。

posted @ 2011-08-11 16:11 Sumtec 阅读(1023) 评论(2) 编辑

2011年3月25日 #

1、4.0的mscorlib里面最占文件空间的类是哪一个?

2、最主要是因为:

A) 对该类及其成员的描述;

B) 该类及其成员的名称;

C) 该类及其成员的签名;

D) 该类中的IL代码;

E) 该类所使用的字符串。

 

曾经有人提出.NET慢是慢在这里,呃,这个我不感兴趣,尽管我怀疑又会再次引起类似的争论。好吧,如果你们非要继续聊这个问题,我先说明我不会参与的。

 

其实这也是一个很有意思的事情,因为有的场景中需要二进制文件大小尽可能的小,比如说所Silverlight。可是,当你看着你的项目越来越大越来越大……为什么呢?不知道。没有调查就没有发言权,所以,只好自行开发一个小工具来研究一下。

 

答案稍后公布。

 


posted @ 2011-03-25 15:51 Sumtec 阅读(1277) 评论(3) 编辑

2011年3月16日 #

摘要: 如果你有新浪微博,请访问:http://q.t.sina.com.cn/618392/invitation_12c95c1-87b6==End==阅读全文
posted @ 2011-03-16 10:04 Sumtec 阅读(293) 评论(0) 编辑

2011年3月11日 #

摘要: 本来我打算等我得出一个明确的、更好的结果之后,再来发表的。但是因为看到一篇错误的结论,实在忍不住了,只好提前写出来。我希望这样能够让更多的人有所进步。昨天在公司随手抄起来一本书,讲的是如何教育小孩的,作者叫郑委(好名字,有官途)。书名倒是不记得了,好像是什么“为了孩子,请家长每天改进自己1%”。书名不是重要的,重要的是,这书里面提到一个什么叫做“智慧”的问题。智慧按照郑委通知的解释(或者他引用的别人的,忘了,这也不重要),应该是“多动脑,少说话”。我这里引申一下:除了管住你的嘴之外,还要管住你的手。为什么我写这个呢,是因为我看到最近一篇博客:文本比较算法Ⅶ——线性空间求最长公共子序列的Naka阅读全文
posted @ 2011-03-11 14:15 Sumtec 阅读(2433) 评论(6) 编辑

2011年3月7日 #

摘要: 我们生活在一个很奇怪的世界中,从小到大经常接受一些很有“意义”的宣传,这些宣传的意义到底是什么很不好说。比如说,我们大多数人从小的教育都应该逃不了“好好学习,天天向上,考个好大学,就能出人头地”。可是事实呢,并非果然如此。其实还有很多人也应该是这么教育的:“你好好学习,考到好的初中(高中、大学),后面就轻松了。”事实上也并非如此。还有一些很奇怪的思想,比如说“上学期间不准谈恋爱”,于是有的乖乖女就真的听话了。当然,最后总还是会发现很残忍的事实——世界并非如同宣传的那样。很多时候我们很容易受到某些形式的宣传所误导,比如说要热爱加班。在我看来,热爱加班和热爱学习其实也没有什么两样,不要浪费时间全副阅读全文
posted @ 2011-03-07 17:57 Sumtec 阅读(2039) 评论(17) 编辑

2011年3月4日 #

摘要: 如果你能认同,世界主要是由傻瓜组成的,那么我们应该都能接受下面这一系列不那么严谨的推论:潮流时兴的东西,通常都是属于傻瓜世界的; =>非傻瓜一定会做一些不常见的事情; =>要脱离傻瓜序列,就需要做所述不常见的事情。上面的说法不能推导出以下的结论:1、非傻瓜一定不做常见的事情。 通常来说,有很多事情只要是个人,都必须做,自然也包括傻瓜。比如说吃饭睡觉呼吸……你懂的。2、做任何不常见的事情就一定能代表你脱离了傻瓜序列。 有些极罕见的行为,比如无缘无故的裸奔,会被傻瓜们视为一个傻瓜行为,这是比较悲剧的。傻瓜们会进一步在自己的世界里面区分出某类人,认为此类人是傻瓜,而自己不是。根据这个描述阅读全文
posted @ 2011-03-04 13:42 Sumtec 阅读(216) 评论(1) 编辑

摘要: 很惊悚的标题,尽管不精确,大概也差不多了。当然,精确地说,世界上所有人并非都是傻瓜。人类的智商从统计学上来说,应该符合t分布,或者类似的分布。反正绝对没脑子的很少,绝顶脑子的也很少,大部分落在被称为“傻瓜”的区间。注意,如果我们把这部分人称为正常人,那么那些能够推动世界发展的人(哪怕是一点点),就绝对不是正常人了。观察这个世界是否主要是由傻瓜构成的,其实有很多方法。最简单的就是观察我们的语言,比如“傻瓜”相机。再比如就是iPhone、iPad等等。说到这里我想特别说一下iOS系列产品,其实这些玩意儿微软系出来的很早,比i系早很多。比如智能手机的WM系,手持设备的PPC系,平板电脑的CE系,等等阅读全文
posted @ 2011-03-04 12:59 Sumtec 阅读(288) 评论(4) 编辑

2011年2月16日 #

摘要: 声明:切勿以此为笔试题。我们很多时候都会激烈的讨论算法、数据结构、设计模式、N层架构、某某框架、系统架构,可是真的在实战当中,才会发现原来有些很简单的问题我们会不知道答案。比如说:[代码]上面的输出是什么呢?这个问题看起来好像很简单,continue不就是进入下一次循环嘛。可问题是,如何进入呢:是直接走到循环最上面的一行代码呢,还是走到循环条件的判断?for、foreach和while都是走到最上面一行代码,而最上面一行代码都存在或者隐含了循环条件的判断。do-while因为循环判断条件在最后,因此不可能同时符合这两个说法,那么到底哪一个说法才是真的呢?这个问题Google之似乎是找不到答案的阅读全文
posted @ 2011-02-16 11:30 Sumtec 阅读(2024) 评论(18) 编辑

2011年1月27日 #

摘要: 这两天发生一件事:有人在一台64位操作系统的IIS上面部署了一个Web应用,结果一访问就显示出错。出错信息如下:Server Error in '/' Application.--------------------------------------------------------------------------------Could not load file or assembly 'MynetMonitorCore' or one of its dependencies. 试图加载格式不正确的程序。Description: An unhandled exception occu阅读全文
posted @ 2011-01-27 16:04 Sumtec 阅读(4456) 评论(24) 编辑

2010年12月24日 #

摘要: 今儿个在首页看到有一新闻推荐,说“程序员在创业团队的技术挑战”。我看了之后仍然还是同样的想法:格局有点小。首先声明一点,这篇文章里面大部分内容我认为说的都是正确的——没错,作为一个程序员,你应该这么做。不过呢,有这么几点我觉得是不太准确的。第一,这里面说的大部分内容,其实无论你在大公司还是小公司,甚至是创业团队,都是可以做的。不存在说在创业团队你才能找到这样的挑战——你的公司没有给你机会,你还是可以自己试一下的。比如说重构你的代码、自动化日常工作、良好的开发习惯、保持你的学习热情等。我想这些内容只要不是在一个很死板的公司,你还是有机会去做的。第二,还有一些内容呢,和你现有的能力以及你手握的权力阅读全文
posted @ 2010-12-24 06:03 Sumtec 阅读(342) 评论(1) 编辑

仅列出标题  下一页