Melchior on CLR

引用类型的开销

值类型与引用类型

C#中的类型分为引用类型和值类型。使用structenum关键字修饰的类型定义是值类型,使用classdelegate关键字修饰的类型是引用类型。引用类型和值类型各有限制,分别适用于不同的场景。不同于C++,C#中的值类型只能分配在栈上*1,引用类型只能分配在GC堆上。C#中的GC是精确式GC,这就对GC堆上的指针有了一些要求。这是引用类型有开销的原因之一。

Sync block index 与 Type object pointer

读过C# vir CLR的同学会知道,引用类型的开销是Sync blockindex和Type object pointer。他们的长度是都是一个字长。即在32位CLR上是4字节,在64位CLR上是8字节。Sync block index在CLR中是用于实现lock,Monitor等线程同步原语,Type object pointer是指向当前对象运行时类型信息的一个指针。Sync block index与Type object pointer只在CLR层面存在,对C#程序来说是透明的。但是CLR将它们暴封装后露C#,例如线程同步原语和反射API。

面向抽象编程

Preface

说来惭愧,直到近几天才明白了一点面向对象设计的。给我带来启发的是SOLID中的D,它代表Dependency Inversion(依赖反转)。尽管写/背定义很无聊,但我还是想写一下依赖反转的核心

上层模块不应该依赖下层模块,他们都应该依赖抽象

Talk is cheap, show me the code

最近在写一个音乐电台应用,采用服务端、客户端的方式实现。在服务端,用户可以指定一个路径,程序根据这个路径生成播放列表。

需求

服务器是一个一旦开起来就不会轻易关闭的程序,我希望播放列表能够自动刷新。这样当用户添加或删除了某首音乐后不用重启服务器就可以反映变化。考虑到易用性,应该支持由路径直接生成播放列表。歌曲是有封面等其他信息的,要满足这些信息的可定制化,程序也支持由配置文件指定的播放列表。

记一次愉(dan)快(teng)的捉虫

废话

BUG是任何软件都会遇到的问题。它通常是开发人员考虑问题不全面而埋下的隐形炸弹,在条件合适的时候就会爆炸;开发自己埋BUG往往比较容易除错,因为代码都是自己写的,定位问题后git blame一下就可以甩锅了;而程序依赖项里的BUG则排查起来则让人一筹莫展,尤其是在没有足够多信息的情况。

面对来自客户和QA的压力,绞尽脑汁仍无法定位问题开发们只能找借口了🤣

  • It’s a feature,not a bug.
  • That’s the design decision, so not a bug

我以前也遇到框架出问题的情况,不过都是自己改代码改出来的,倒也不是很难排查。但这次挖出来的BUG就完全不一样了

闭包,变量捕获与重入问题

问题描述

公司的APP,在断网后进行一个10秒的倒计时操作,每秒钟都会尝试重新联网。当秒数到0时又重新开始计时,倒计时在用户退出程序或者连上网络结束。

按理说是个很简单的Case。QA却报过来个BUG,说APP状态由

联网->断网->联网->断网

变化后,倒计时的秒数变为

9 3 8 2 7 1

变得不连续了。

HTTPClient 踩坑记

HttpClient是随着.Net framework 4.5一起发布的现代Http库。比起WebClient,HttpClient最大的优点就是
加入了C#5中的async/await异步方法的支持。async/await的坑暂且不表,今天就来说一说这个HttpClient

HttpClient的坑

HttpClient实现了IDisposable接口,很多小伙伴一看到IDisposeable接口就纷纷把HttpClient套在了using里边

1
2
3
4
5
//bad httpclient usage
using(var client = new HttpClient())
{
//do stuffs
}

这种用法是错误的.HttpClient在设计之初被设计为一个可重用的对象,它的生命周期应该与应用程序相一致.上述错误的用法每发起一个请求就会创建一个新的HttpClient,并且在收到回复之后立即把HttpClient dispose掉。众所周知TCP连接在真正断开之前会有几分钟处于CLOSE_WAIT状态。这个状态下TCP链接并没有真正断开。短时间内大量发出Http请求会使系统可用的端口急剧消耗。