https://www.cnblogs.com/junchu25/archive/2012/08/10/2631422.html

上周四产品上线一切运行正常,做了一点小改动后周四晚上发布,周五大量用户反馈在访问页面时出现长时间等待响应。将4台Web前端的服务器重启,缓存服务器2台重启,问题依旧。由于是生产环境,只能上去查看IIS、Windows日志,没有记录任何异常。于是将版本更新回周四凌晨发布版本,运行正常。据版本跟踪只修改过一个特定模块,但是这个模块不会影响页面的正常访问。于是猜测可能是短时间的网络问题,IIS在这个时间段没有请求访问的日志,不会是程序的性能问题。于是晚上在集成环境恢复周四晚上发布的版本,问题重现,但是周四早上的版本没有问题。

任务管理器显示w3p进程的内存、cpu使用率、线程数都没有变化,应该是一个deadlock。但是周四晚上发布的版本并没有添加或修改过线程同步的代码。对发布的dll进行跟踪排查,发现Memcached.ClientLibrary.dll的大小和早上发布的版本不同。晚上发布的是Debug版本,将Memcached.ClientLibrary.dll更新为Release版本问题解决。于是问题就产生了,为什么Debug和Release版本在同一个环境下,Debug版本会造成deadlock。

用WinDbg附加到w3p进程,进行压力测试,30 – 50用户下出现deadlock。用!runaway查看线程使用cpu时间,大量线程使用cpu时间为0。用~* kb查看所有call stack,大量线程都在等待ntdll!NtWaitForMultipleObjects。用!cs查看临界区,内容太多。修改HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\CriticalSection-Timeout的值为60,便于WinDbg获得更多的超时信息。加载sos.dll,!threads查看所有托管线程,发现一个线程抛出了System.Threading.SynchronizationLockException。用!SyncBlk查看托管代码的lock情况,发现存在两个实例lock和一个RuntimeType lock。继续用~* e !clrstack查看所有的托管线程callstack,发现大部分代码停留在SockIOPool的CheckIn函数,小部分停留在SockIOPool的GetInstance函数和RemoveSocketFromPool函数。根据!SyncBlk显示的三个线程ID,用~线程ID s命令切换到对应线程查看callstack。使用实例lock的线程停留在RemoveSocketFromPool函数,使用RuntimeType的线程停留在CheckIn函数,抛出SynchronizationLockException的线程则停留在GetInstance函数。

于是分析Memcached.ClientLibrary.dll的源代码,发现它在几个函数上使用了MethodImplAttribute,并将函数的属性标示为Synchronized。对于MethodImplOptions.Synchronized,如果函数为static那么它使用RuntimeTypeHandle作为lock,实例函数则使用this指针作为lock。CheckIn为实例函数,而GetInstance、RemoveSocketFromPool为static函数。由于内部代码创建了两个SockIOPool实例,所以在callstack中可以看到它们分别停留在RemoveSocketFromPool函数(CheckIn函数内部会调用RemoveSocketFromPool函数),证明有两个线程独占了this指针。而另一个线程停留在了CheckIn函数,在CheckIn函数前会先调用GetInstance函数,所以它lock了RuntimeType,但正常情况下在调用完GetInstance函数后不应再独占资源。这就是一个典型的deadlock,有两个线程锁住了this指针同时在等待获取RuntimeTypeHandle,而一个线程锁住了RuntimeTypeHandle,同时在等待获取this指针。

知道了现象后情况就很容易模拟,编写一个Console程序部署到x64的机器上运行,问题重现。但是这个问题在x86的机器上没有问题、在x64机器上以x86的兼容性运行也不会存在deadlock。于是大致情况可以确定在x86的机器上编译的Debug版本在x64机器上运行会出现deadlock。通过ildasm查看Debug和Release在IL层级的区别,发现MethodImplOptions.Synchronized会被修饰为cil sync managed,看来这层操作只有在JIT后才会看出代码的区别。

这个时候在Microsoft的Connect上发现有人曾经在09年4月份反馈这么一个现象,当时给出的workround就是使用显示的lock代替MethodImplOptions.Synchronized,同时会在下一个版本的CLR修复。为了验证是否在下一个版本的CLR修复,将同样的测试代码运行在.NET Framework 4.0下没有问题。

警惕32位程序在MethodImplOptions.Synchronized在x64机器上的同步缺陷[z]的更多相关文章

  1. 64位系统上运行32位程序能否申请到8G内存?

    申请不到,因为64为系统在运行32位程序的时候只是为了向下兼容而已,对于32位程序来讲,申请8G的存储空间没有任何意义,因为32位的程序最大寻址空间只有4G,32位程序在编译之后的机器代码也只有32位 ...

  2. 转:如何在32位程序中突破地址空间4G的限制

    //如何在32位程序中突破地址空间4G的限制 //首先要获得内存中锁定页的权限 #define _WIN32_WINNT 0x0501 //xp系统 #include <windows.h> ...

  3. 64位Ubuntu运行32位程序时报文件不存在(No such file or Directory)的一种解决办法

    尝试在64位Ubuntu下面运行32位程序时, 一直说 文件不存在(No such file or directory), 我只想说++. 你tm说个文件格式不正确不就好了? 非得说个文件不存在! 真 ...

  4. 记32位程序(使用3gb用户虚拟内存)使用D3DX9导致的一个崩溃的问题

    为了增加32位程序的用户虚拟内存的使用量,我们使用了/LARGEADDRESSAWARE编译选项来使32位程序可能使用到3gb的内存,能否使用到3gb内存也跟平台.系统和设置有关系,现摘抄部分作为参考 ...

  5. Ubuntu14.04 64位运行32位程序

    最近公司新增的机器安装Ubuntu14.04 64bit导致之前在32bit下编译的Qt工具软件无法运行. 于是google的了一下找到一些解决办法,但不能保证全部32bit的Qt程序都能正常,测试了 ...

  6. Linux 64位编译\链接32位程序

    测试机器:Ubuntu14.04 64位 gcc编译32位程序,添加参数-m32: $ gcc -c -fno-builtin -m32 TinyHelloWorld.c ld链接32位代码,添加参数 ...

  7. "用wow64exts调试64位任务管理器抓取的32位程序的dump"

    博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:"用wow64exts调试64位任务管理器抓取的32位程序的dump".

  8. 关于32位程序在Win7&64位系统中连接Microsoft Excel数据源的问题

    最近在新公司电脑上跑以前的selenium测试框架的时候,抛出了如下的错误 出现的是ODBC Driver问题:[Microsoft][ODBC Driver Manager] Data source ...

  9. 32位程序调用Oracle11gR2数据库libclntsh.so失败

    [问题描述]32位程序调用Oracle11gR2数据库的libclntsh.so库时会返回失败. [问题原因]32位程序只能调用32位的Oracle客户端实例包,而R2数据库默认安装完毕后是没有lib ...

随机推荐

  1. net start mysql意外终止1607

    以下个人见解,错了请指出,谢谢 问题:安装了mysql,看到别人都用net start mysql来启动mysql服务,结果我打开cmd,用net start mysql 就会出问题.在网上查资料,好 ...

  2. 微信小程序是怎么运行的?

    微信客户端在打开小程序之前,会把整个小程序的代码包下载到本地. 紧接着通过 app.json 的 pages 字段就可以知道你当前小程序的所有页面路径 而写在 pages 字段的第一个页面就是这个小程 ...

  3. vs2017安装和使用教程(详细)

    借鉴:https://blog.csdn.net/qq_36556893/article/details/79430133#一.官网下载

  4. IDEA overwrite报错、languagelevel设置不生效问题

    发现idea 倒入项目后,发现@override报错,发现是idea的jdk版本不对,需要设置大于1.5的jdk版本 解决办法: IDEA:File >> Project Structur ...

  5. Linux守护进程管理利器——Supervisor

    Supervisor是采用 Python(2.4+) 开发的,它是一个允许用户管理 基于 Unix 系统进程的 Client/Server 系统,提供了大量功能来实现对进程的管理.安装: yum in ...

  6. eShopOnContainers 看微服务④:Catalog Service

    服务简介 Catalog service(目录服务)维护着所有产品信息,包括库存.价格.所以该微服务的核心业务为: 产品信息的维护 库存的更新 价格的维护 架构模式 先看代码结构(下图). 主要依赖: ...

  7. SAP Solution Manager 能够连接到 SAP Service Marketplace

    使用 在该步骤中,您要确保 SAP Solution Manager 能够连接到 SAP Service Marketplace. 作业 SAP Support Portal(SAPOSS)的 RFC ...

  8. HTML5 使用 JS 生成二维码,带头像

    一般在项目开发中,前端显示给用户扫描的二维码基本都是由后端代码生成的,那么这个高大上的功能能不能用 JS 来绘制呢? 答案是肯定的 首先我们需要一个插件 jquery.qrcode.js,该插件基于  ...

  9. OpenStack构架简介

    OpenStack既是一个社区,也是一个项目和一个开源软件,提供开放源码软件,建立公共和私有云,它提供了一个部署云的操作平台或工具集,其宗旨在于:帮助组织运行为虚拟计算或存储服务的云,为公有云.私有云 ...

  10. ---rk3288 mipi 整发(适用于新版的kernel 4.4 )

    http://www.pianshen.com/article/7245318143/ 老的Anroid 5.1 下 Linux 3.10 的数据的名字和 处理方式有不少不同 不过rk3128 还在走 ...