.Net网站程序疑难杂症Dump内存分析

有些时候.Net的站点在测试时没问题,上到正式环境出现CPU 突然占用100%的问题,或者突然进程崩溃的问题,当代码量比较大的时候,基本上完全无法下手找到问题,在系统的日志里你也找不到任何有用的信息。这时候几乎只能依赖于Dump内存进行分析,查看当时情况下的进程中正在执行的过程,来查找可能出现问题的原因。
对CPU占用100%的问题处理:
ProcDump 8.0下载,只有一个400K主程序,不需要其它附加内容。
当指定进程的CPU占用超过30%连续3秒的时候抓取完整dump,抓取2次后退出。
另外在进程执行过程中抓取之前,程序中触发的异常信息也会直接显示在命令行窗口中。

procdump -ma -c 30 -s 3 -n 2 -e 1 -f “” 5960(Process Name or PID) -o E:\Procdump\Log

    -ma 生成full dump, 即包括进程的所有内存. 默认的dump格式包括线程和句柄信息.
    -c 在CPU使用率到达这个阀值的时候, 生成dump文件.
    -s CPU阀值必须持续多少秒才抓取dump文件.
    -n 在该工具退出之前要抓取多少个dump文件.
-o dump文件保存目录.
其它可用参数:
-t
Write a dump when the process terminates.
-m
Memory commit threshold in MB at which to create a dump.
-e Write a dump when the process encounters an unhandled exception. Include the 1 to create dump on first chance exceptions.
分析Dump还是需要用windbg(安装WindowsDevelopKit):
打开windbg,将对应的Dump文件拖进来,先加载.Net符号文件:
.load C:\Windows\Microsoft.NET\Framework64\v4.0.30319\sos.dll
然后:
!threadpool,查看线程池的CPU使用量
!runaway,查看线程占用CPU时间
~28s,切换到28这个线程(占用CPU前几名的程序,可能都需要切换过去看一下)
!clrstack,到具体某个线程后,查看当前线程中正在执行的托管代码,到这一步基本就可以看出问题
其它命令:
!analyze -v 自动分析异常信息
输出信息中的关键信息:
然后进入43这个进程,查看托管代码:
基本可以锁定是由于Senparc这个库里面的LocalCacheLock中的RetryLock方法导致的死锁。
另外!dumpstack -ee也可以用来查找异常信息
对进程自动崩溃的问题处理(系统事件查看器中显示StackoverflowException,此异常用try catch无法捕获):
除上面的procdump -t方法之外,还可以用windbg中包含的adplus工具来生成dump:
adplus -Crash -pn w3wp.exe -FullOnFirst -o d:\output
对生成的Dump文件的分析方式同上。

Yosemite DP3+iOS8 Beta3 Handoff打电话功能测试

8号一大早就把手机和Mac都升级到了最新的测试版,DP3+Beta3,出现了Handoff开关,但是电话和短信进来的时候Mac上死活就是没反应,在网页上选中电话号码或者在Mac的通讯录里查看电话,也不会出现打电话的图标。查看了很多次,iCloud都已经使用同一个账号登录了,而且在DP2的时候Mac上就提示过你的iPhone已经可以使用Continues功能了。

今天才偶然在威锋论坛上看到一个帖子,原来是需要用同一个账号登录Facetime,恍然大悟。打开Facetime一看,以前用的是另外一个AppleId登录的。重新登录之后打开Facetime的偏好设置,允许联系的方式里面确保手机号已经被选中,下面的iPhone(蜂窝通话)功能选中,就OK了。

再回到通讯录里,每个号码的旁边就会直接出现了拨号的电话图标,在网页上双击选中一个手机或固话,就会出现下拉箭头,里面就有呼叫的菜单了。尝试着通过Mac直接发起呼叫一个号码,不知道是不是因为公司WIFI的问题,反应有点迟钝,接近半分钟以后,手机上出现了通话的信息(就是通话中按Home键回到桌面的那个状态),然后对方接起来之后就可以在Mac上直接通话了,通过过程也有延迟,但是没有那么明显,基本可以接受。用带耳麦的耳机直接插在Mac里打电话也可以,不过对方听到的噪音会比较厉害,缺少了iPhone上的降噪功能。

iOS8地理位置编程的奇葩改进

一个很简单的iBeacon的测试程序,以前都好用的,手机升级到iOS8 b2,xcode6 b2编译运行,就不能正常工作了,总是提示位置授权状态是kCLAuthorizationStatusNotDetermined,进到设置里隐私-地理位置下面找到这个应用,设为总是允许,再重新编译运行,它又会变成这个未知状态。看了文档加上搜索了很多次,都是说当弹出授权对话框的时候如果用户没有选同意,就会出现这个状态。可是,我这应用根本就不会弹出让用户授权的对话框啊。

以为是xcode的Bug,今天等到了beta3,结果还是同样的情况。又重新开始搜索,这次终于找到了眉目。

首先,原来的代码只要走到locationManager startMonitoringForRegion的时候就会自动弹出询问授权的对话框,而现在你需要调用locationManager requestAlwaysAuthorization手动申请授权,并在didChangeAuthorizationStatus这个回调里面继续后面的开始监测的代码。

其次,最坑爹的是,当你调用这个request的时候,它弹出的对话框里面的那句询问语,需要你自己指定。所以需要在你的info.plist里面添加一个key: NSLocationAlwaysUsageDescription,value就是对话框上那句询问语。这时候程序才能正确的弹出授权对话框,用户选了同意以后,程序后面的代码才能够正确的运行。

MISFit Shine简单体验

misfit shine

 

一直很想买个“智能”手环玩玩,但是现有的几个设备外形完全不符合我的审美,另外就是充电的问题也很让人讨厌。偶尔在威锋商城里看到了misfit shine的说明,眼前一亮,这才叫低调啊。

实际的产品比图片给人的感觉还要小一些,主体部分基本相当于一枚1元硬币的大小,对我这种手腕比较细的人来说,是个合适的尺寸。开箱图就不上了,里面除了主体设备,还有一个腕带一个磁性夹扣带,一枚2032钮扣电池,一个圆形的拆机卡片。抠开后盖,放入电池,再原样盖上去。据说整个外壳是一块铝材抠出来的,跟苹果家的设备制造方式一致。不过这样简单的扣上去的后盖实在让人不敢相信它的防水能力。不过按照官方说法游泳也是没有问题的,但是带着洗澡可能会有问题,热水会导致后面密封不严。据说这么一枚钮扣电池可以用4个月,仅凭这一点优势,就足够了。

打开手机应用,设置账号登录,设置个人的身高体重,设定你每天想要达到的运动目标,同步一次设备,然后就可以用了。

它最大的弱势是监测能力不强,只有运动监测,其它的心跳脉搏血压什么的一概没有。连夜间的睡眠跟踪也是靠运动监测实现的,所以不是很准。手机端的软件经过N次升级,已经具备了自动睡眠跟踪和自动唤醒功能,不过两个功能实现的都有些问题。在自动睡眠跟踪这个功能出现之前,你要在睡觉前敲三下让它进入睡眠模式,现在变成自动的,它会在夜间根据你的运动情况自动判断是否进入了睡眠状态,另外也有深度睡眠时间的检测,不过实际用下来,这个是比较扯淡的。自动唤醒功能就更扯了,设备本身根本就没有加入震动和声音的功能,所以唤醒是要靠手机端的软件的,而要实现进入轻度睡眠时唤醒,也不可能提前设定好固定的唤醒时间,必须根据设备的运动监测来实时判断,所以,你要使用这个智能唤醒功能,手机端的软件必须常开,而且不能进入后台,不能锁屏,所以它还提供了一个暗屏状态。在设定的唤醒时间之前的半小时内,手机端软件会跟设备实时同步,在认为你处于浅睡眠状态时播放铃声来叫醒你。这就更扯淡了。因为添加了自动睡眠跟踪功能,所以轻敲三下可以加上另外一个功能,切换当前的运动模式,对于一些有着固定健康项目的人,可以设定为自己的健康项目,比如骑车游泳篮球,在这个模式下可以得到更准确的运动数据。

设备没有屏幕,只有一圈12个LED灯,这12灯确实也是这个设备的精华所在。轻敲两下,会先显示你今天运动的目标进度,然后会显示当前时间,时间是以时针作为常亮分针作为闪烁来显示的,还算是比较方便,不需要经常同步就可以看当天的运动程度。同步后在手机上可以看走了多少步多少距离,这个距离是根据你的身高自动算出来,只是个近似值。

总体来说,shine的亮点一是精致美观,黑色款纯黑的表面加上亮银的四周,非常漂亮,二是不需要经常充电。缺点嘛就是没有GPS,也没有其它健康监测的功能,它所能提供的就是你为了达到自己所设定的运动目标提供一个激励方式,另外App端也提供社区功能,可以跟朋友一起PK之类的。

更有效的全网页深度抓取(样式+图片)

通常情况下的网页采集一般是指我们想要抓取整个站的页面内容,从首页开始,然后分析整个页面里的a链接,然后把链接指向的页面再取出来,然后再往下一层去采集。这种情况下,只需要分析a元素或者链接的正则就可以了。但是还有一种情况,我们想保存一个完整的网页内容下来到本地,希望它能够还原整个访问的体验,以便在离线时也可以使用,这样就需要保存下完整的js和css以及图片等。但是有些网页使用的css做了多层import嵌套,而有些图片还是通过js等方式后加载的,如果要写出一个完整有效的分析代码然后能够层层获取,并不容易。

这时候有一个更简单有效的方式,就是让浏览器告诉你哪些内容是显示这个页面需要的,是你需要保存下来的。而有些css(甚至大部分)中出现的样式和图片,在你想要的这个页面里并没有被用到。怎么做呢?用proxy方式。

接下来就要用到nodejs出场了。用express建立一个简单的网站,express –sessions proxy1,然后这个默认模板下面的public, views, routes等目录可以全部删掉。在package里添加上依赖包request和mkdirp,这就够了。

然后修改app.js,我们要怎么做呢?先把端口改成80,然后下面的route部分,直接加一个app.get(‘*’, function(req, res){});,由它来接管所有的路径请求。然后在这个函数中,我们需要让站点起到代理的作用。此时过来的访问请求的路径在变量req.originalUrl中,我们要把这个请求转发到原网站上去。所以在这里把原网站的域名加上去,var url = ‘http://www.sample.com/’+req.originalUrl,然后把这个请求交给request包去获取。request(url)得到的是一个读取流,基于nodejs的流机制,你可以把它直接pipe给输出流。比如下面写上这样一句:request(url).pipe(res); 这样request就直接去获取这个远程URL并把取到的内容直接转交给了response输出。我们的代理就完成了。

那么怎么来测试这个功能呢?只要node app.js启动你的本地站点,用浏览器访问http://localhost/some/url,访问任何路径,域名后面的部分都会被转发到你要抓取的网站上对应的URL上去,页面的内容都被被nodejs取回来并转发回你的浏览器,理论上,你的浏览器看到的页面内容应该是跟直接访问对方网站没有任何区别的。而且,在这个过程中,浏览器会负责解析现在需要加载哪些js,包括js中的再引入,还有css中的import,以及css样式多层覆盖之后实际需要的背景图片之类的。

这个时候,我们只要稍加改造,就可以让这个proxy做点贡献了。我们只需要把request取到的东西先保存下来,再返回给浏览器就可以了。经过试验,这个pipe貌似并不能转发两次,比如先转发给一个文件写入流,再转发给一个response写入流。那么我们只好把过程分开了,

        var writestream = fs.createWriteStream(file);
        writestream.on('close', function (result) {
            var readstream = fs.createReadStream(file);
            readstream.pipe(res);
        });
        request(url).pipe(writestream);

这里的file参数,就是根据文件的URL,去除了路径后面的参数,加上你要保存的路径,拼起来的一个绝对路径。当然,在写入文件之前,你需要检查一下它的路径是否存在,不存在的话需要先创建路径,这时候就要用到mkdirp了,可以一次创建多层路径。

这个过程写完,再用浏览器访问你的代理服务器,这个页面需要的所有文件都保存在你的本地了,而且保持着相对路径。

剩下的还有一点小优化,比如有的网站页面里的链接、js、css引用的时候全部写绝对地址,那你用localhost访问的时候,只有第一个页面的HTML会经过你的代理,后面的所有的请求都直接回到他的网站上去了,不经过代理了。这时候就要用到另外一台机器(比如虚拟机),把这个域名的IP直接指向你的这台机器的IP,再用浏览器访问他的绝对路径,所有的请求都会到你这儿,再由你的机器去访问真实的路径。为什么要用另一台机器呢,因为如果在你的这台机器上直接改了域名的IP指向,那你的代理服务器本身也访问不了他的网站了。

另外一个需要处理的是,在返回的内容中把可能存在的绝对路径替换掉。换成相对路径。这样保存在本地的所有内容才是可以原样打开的。

这样抓下来的页面,基本上是完整的。(除了ajax请求的部分和流媒体的部分)当然,ajax请求如果是本站内的请求,你也可以把路径替换成相对路径,然后在本地再打开的时候不是直接双击首页文件打开,而是通过nodejs建一个本地服务器来打开,其实应该也是支持的。

在IIS里运行nodejs站点

这是一个很神奇的功能,可以让你的nodejs开发的web server程序直接运行在iis里面,由iis作为deamon程序,即可以解决nodejs本身的单进程单线程问题,又可以实现把nodejs站点托管到80端口上的功能。而且,nodejs的站点即可以作为一个独立的站点来运行,也可以作为已有的asp.net网站中的一个虚拟目录来运行,完全没有影响。微软对nodejs的社区还是提供了很大的支持的,比如官方提供了sql server的nodejs驱动。

要实现这个功能,基于这样一个项目:https://github.com/WindowsAzure/iisnode,它实现的是一个IIS Module,全局加载到IIS中以后,就可以在任意一个站点中,通过Web.config来指定把某些路径转交给node程序来解释执行,同时可以配置一些额外参数,比如启动多少个nodejs进程,每个进程最大允许多少个连接,允许多少个等待中的连接等等。而且这个module本身还有监视站点文件变化的功能,当你修改了某个js文件,它可以自动重启加载。

你可以下载项目的源代码,自己编译,也可以下载官方已经提供的安装程序。(必须使用安装程序,因为注册为IIS Module需要一些系统注册动作,因为一开始一直找不到最新版的官方的安装程序,就想自己编译一个,结果vs2013又不支持wix项目,只生成了两个dll,修改iis全局配置,搞了几个小时也没有生效,后来找到安装程序以后一下子就成功了。当然,也是因为一开始没有读清楚这个项目的页面上写的编译说明,没有安装http://wix.codeplex.com/这个东西,其实要自己编译生成安装程序还是比较容易的。)推荐windows server 2008及以上,IIS7以上。

首先需要在你的服务器上安装node,建议也使用安装程序吧,可以自动帮你设置path。安装了node以后再安装iisnode,你可以使用这个地址:iisnode-full-iis7-v0.2.7-x64-2.msi。安装完以后它的安装目录下有个www目录,还有个安装测试站点的bat脚本。如果有兴趣你也可以直接使用这个脚本,它会在你的IIS的默认站点下建立一个node的虚拟目录,指向这个www,这样就可以直接看到下面提供的五个测试站点了。

web.config里面只有一句比较重要,就是一个handler配置,你可以把站点中的启动文件,比如app.js,指定用iisnode这个module来托管。然后在浏览器中打开localhost/node/app.js,就可以看到执行结果(如果你的app.js里没有引用非node基本模块的话)。

如果你的项目使用了基本模块之外的依赖,那就需要先npm install一下,这个过程可能很顺利,也可能很痛苦,如果你要安装的东西不需要根据平台重新编译,安装就会直接完成,但是如果需要重新编译,那就比较麻烦,你需要安装visual studio。目前你可以选择在服务器上安装visual studio express 2012 for windows desktop,千万不要装错。中文版大概是一个600多M的iso文件,直接安装就可以。安装完成以后再运行npm install –msvs_version=2012(如果不加这个参数,默认是2010版的编译程序,应该会提示无法加载vcbuild.exe之类的错误)可能还会看到一些警告,不过正常来说应该能编译通过了。不过也有些还会继续有依赖,比如crypt,它需要openssl的头文件。你要下载一个16M的64位windows的完整版openssl,安装到C盘,再来运行npm install。另外也有一些模块依赖的头文件只有unix系统上有提供,那就只好完全放弃了。比如sleep,完全无法编译通过,只能放弃这个函数,改用setTimeout来解决。

做完这些以后,我的整个demo项目的代码就可以完全跑起来了(前提是你还安装好了mongodb的windows版并已经启动)。测试了一下,速度相当快。启动了两个node进程,只占用了150M内存。

另外,还有一点需要处理,就是URL映射。可以通过IIS的urlrewrite模块,把public下的静态文件直接rewrite到文件目录,由IIS来直接提供,不经过node,然后其它路径全部rewrite到app.js上。这时候在node里面看到的程序路径是当前访问的完整路径,所以如果你把这个项目放在一个虚拟路径下,那么在app.get(‘/’)这个url的时候,就要把虚拟目录这一层加进去才可以了。

这样,就你可以在整个asp.net的站点下,把一部分功能交给nodejs来完成。比如,nodejs最擅长的RESTFul形式的api,以及访问量巨大但单个请求负载不高的内容。