当前位置: 首页 > 编程日记 > 正文

[译]怎样用VisualStudio查看非托管代码

(译者:这篇文章作者是一位美国的MVP,这是他的系列文章"Under the cover"的第一篇,文章的本意从最底层的角度来优化代码的性能,并作为阅读作者其他文章的技术基础,这种通过这样的做法虽然初看起来有些过分,但是对读者了解.Net许多底层运作是十分有益的)

我们从使用visual studio进行非托管代码调试的基础开始,以便大家可以更容易的学习今后的例子,并让这篇文章作为我以后文章的基础,虽然我也使用windbg,但visual studio已经成为了一个功能强大的调试工具,对于简单的代码优化问题反而更容易使用

当我们需要校调对性能要求很高的代码时,查看IL通常不是最好的做法,因为JIT优化器会默默的优化我们的代码,使用reflector或者ildasm你能很快发现release和debug模式下产生的IL代码几乎完全相同,那么是什么让release模式的代码运行起来如此迅速呢?这就是JIT优化的结果,通过查看managed代码(IL代码),我们没有办法看到这些优化,所以我们将通过native code(本地代码)来查找蛛丝马迹。

必须说明我不提倡大家经常这样做,我不赞成过早的进行优化,你必须使你的代码先工作起来,你必须清楚的知道哪些代码是不值得优化的,当你的代码完成后再来找那些需要提速的地方,当你发现有的地方10% 的代码却使用了70%的时间的时候,再回过头去优化那10%的代码.同时你总是应该把判断的依据建立在对速度的实际测量上,而非仅仅是阅读代码,最后,其实数据结构的选择比底层的优化重要的多

当然话又说回来,了解隐藏在.Net底层的秘密是非常有趣的,那就让我们开始设置visualstudio,并动手试验一个简单的例子

首先我们需要一些试验代码

static void Main(string[] args) {

for (int i = 0; i < 10; i++) {

Console.WriteLine("Hello World!");

}

}

为了打开非托管代码调试,我们需要对visual studio进行设置.打开项目的属性并进入Debug Tab,选择该页上的“Enable unmanaged code debugging”复选框

original.aspx

(注意,这个选项只对当前使用的配置有效,因此我们应该为我们使用的所有配置设置这个选项.)在循环的开始处插入一个断点,并运行程序,你将会像往常一样击中一个断点。这时你的屏幕应该看起来如图二(译者:原文缺图)如果你没有stack窗口,可以通过menu -> windows -> call stack (或者  ctrl + d  c)将其呼出,打开call stack后,我们就可以通过右击鼠标,选择go to disassembly进入下面的代码

static void Main(string[] args) { 00000000 push ebp 00000001 mov ebp,esp 00000003 push edi 00000004 push esi 00000005 push ebx 00000006 sub esp,38h 00000009 xor eax,eax 0000000b mov dword ptr [ebp-10h],eax 0000000e xor eax,eax 00000010 mov dword ptr [ebp-1Ch],eax 00000013 mov dword ptr [ebp-3Ch],ecx 00000016 cmp dword ptr ds:[00912DC8h],0 0000001d je 00000024 0000001f call 792B228E 00000024 xor esi,esi 00000026 xor edi,edi 00000028 nop for (int i = 0; i < 10; i++) { 00000029 xor esi,esi 0000002b nop 0000002c jmp 0000003D 0000002e nop Console.WriteLine("Hello World!"); 0000002f mov ecx,dword ptr ds:[022B303Ch] 00000035 call 785D9074 0000003a nop } 0000003b nop for (int i = 0; i < 10; i++) { 0000003c inc esi 0000003d cmp esi,0Ah 00000040 setl al 00000043 movzx eax,al 00000046 mov edi,eax 00000048 test edi,edi 0000004a jne 0000002E } 0000004c nop 0000004d lea esp,[ebp-0Ch] 00000050 pop ebx 00000051 pop esi 00000052 pop edi 00000053 pop

我们正在查看的就是JIT为我们的代码产生的native code(本地代码),我们可以看到简单的循环在native code层次上怎么运行的,如果你从来没有研究过native code,这些本来很普通的代码可能看起来相当的奇怪,让我们来自己看看这里发生了什么

00000029  xor         esi,esi

0000002b  nop

0000002c  jmp         0000003D

上面代码初始化我们在ESI中的计数器,ESI是一个索引寄存器,可以用来索引数组,你可以看到这里用了一个很古老的"把戏"来把计数器清0,代码没有使用把0值放入寄存器,而是让寄存器自己异或(xor)自己来达到清0的目的,接下来的一行Nop,意思是"没有操作",而他们的作用就和他们的名字一样,什么也不做,代码接下来立即跳转到3D.有时候像这样的跳转使得我们的代码不是自上而下的运行(就象许多高级语言比如c,vb,c#里面一样),如果跟着这个跳转进入这个循环的另外一个部分,就可以继续分析我们的代码

0000003c  inc         esi

0000003c后面第一个指令把ESI中的计数器加一(通过register窗口或者组合键ctrl+D R  你可以看到它的值),在第一次循环时代码会跳过这行,因为上面的跳转指令直接指向了0000003D


0000003d  cmp         esi,0Ah

00000040  setl        al

00000043  movzx       eax,al

00000046  mov         edi,eax

00000048  test        edi,edi

0000004a  jne         0000002E

从0000003D开始到4a,代表于循环停止值的实际比较和跳转如果我们没有达到这个值(i<10),最后一行会跳转到2e(译者注:原著这里为4a,是个笔误)继续这个循环,也就是循环体开始的地方
0000002f  mov         ecx,dword ptr ds:[022B303Ch]

00000035  call        785D9074

上面的第一条行将会把字符串从从内存装在到ECX 寄存器 (这是一个通用寄存器), 一般ECX总是用作把第一个参数传给方法,在实例的方法中,ECX将总是包含this,紧接着是包含第二个参数的EDX,然后是一系列的push,用于把其他参数入栈

下一条语句执行实际的调用。我们待会再来探讨怎么去查找所调用的方法,但是现在我们可以从VisualStudio给出的源代码看到,这毫无疑问就是 Console.WriteLine ,代码接着执行索引的自增,并返回来继续执行loop循环内部的代码

然而,我们的微不足道的例子中已经产生产生了明显的浪费。下面是一个例子
00000009  xor         eax,eax

0000000b  mov         dword ptr [ebp-10h],eax

0000000e  xor         eax,eax

00000010  mov         dword ptr [ebp-1Ch],eax

我们在一行里两次对EAX置0,这时因为我们正运行在debug模式下,调试模式下是不进行优化的,换句话说,这段代码只是被JIT执行,但是却没有允许JIT作任何智能优化

下面让我们来看看经过优化的代码:

这里有一些关于查看优化代码的问题
1)是调试器默认关闭了JIT的优化(我自己就曾经在大半夜花了很长时间才意识到自己一直在看没有被优化的代码)
 2)是必须处理"Just My Code"选项对优化代码的影响

我最初在Vance Morrison的帖子上看到了解决这个问题的办法(谢谢 Vance,我已经被整个问题困扰了很长一段时间,并最终使用直接查看没有源码的原始assemble的方式).

要搞定这个问题,清跟着以下的步骤作

1) 打开 Tools -> Options -> Debugging -> General

2)确保 ‘Suppress JIT optimization on module load’没有被选中

3)也确保‘Enable Just My Code’没有被选中

original.aspx

Vance 也建议我们进入advanced build设置release dll为pdb only,这时我们可以用前面同样的方式运行这段代码

用 JIT 看我们的代码另外一种方式是使用release模式,使用Start the executable without the debugger,再附加visualstudio到进程进行调试.

使用任一方法我们都能让 JIT 将代码优化了。得到优化的代码如下

for (int i = 0; i < 10; i++) { 00000000 push esi 00000001 xor esi,esi Console.WriteLine("Hello World!"); 00000003 cmp dword ptr ds:[02271084h],0 0000000a jne 00000016 0000000c mov ecx,1 00000011 call 786FC654 00000016 mov ecx,dword ptr ds:[02271084h] 0000001c mov edx,dword ptr ds:[0227307Ch] 00000022 mov eax,dword ptr [ecx] 00000024 call dword ptr [eax+000000D8h] for (int i = 0; i < 10; i++) { 0000002a add esi,1 0000002d cmp esi,0Ah 00000030 jl 00000003 00000032 pop esi } } 00000033 ret

哇,这次的代码比第一次少多了,JIT 优化确实工作的很好,这就是为什么查看实际的反编译代码而非IL是这样重要,因为JIT经常会通过识别IL中的模式来进行优化,机敏的读者可能注意在我们的循环的内部事实上产生了更多的密码。初看起来这是非常可怕的,但其实这说明优化器已经帮助我们inline了Console.WriteLine方法,实际是节省了很多代码在接下来的帖子中我会谈到inline,但是大家先明白这是一个很重要的优化

我们这时已经准备好了怎样在调试器中去欣赏优化的和没有优化的代码,我想这是一个好的开始,下面的几个帖子我会为更深入的了解JIT的一般优化过程而打好基础,我们也可以接触一些工具,看看他们会怎样帮助我们得到更好的代码

希望能在那里见你。

原文地址

http://codebetter.com/blogs/gregyoung/archive/2006/06/09/146298.aspx

原文的一些资源:

http://en.wikipedia.org/wiki/X86

http://www.codeguru.com/csharp/.net/net_general/il/article.php/c4635/ IL tutorial

http://burks.brighton.ac.uk/burks/language/asm/asmtut/asm1.htm ASM tutorial

转载于:https://www.cnblogs.com/yizhu2000/archive/2007/08/08/848160.html

相关文章:

盘点互联网大厂AI战略变迁,开发者将怎样pick前进路线?

随着各大企业相继试水“全面 AI”&#xff0c;人工智能在技术落地层面也开始持续深入&#xff0c;泛人工智能时代正在逼近。越来越多的发展趋势表明&#xff0c;未来的人工智能将逐步迈入广泛普及阶段&#xff0c;继而深入影响人类日常的生产生活方式&#xff0c;重塑传统生产结…

druid拦截器_CMS基于SpringBoot+Shiro+Mybatis+Druid+layui后台管理系统

contentManagerSystem后台管理系统简介contentManagerSystem,后台管理系统,采用SpringBoot构建整个项目框架,apacheShiro权限验证&#xff0c;mybatisdruid数据持久化动作,前端采用layui(http://www.layui.com/)展示&#xff0c;整个项目全部通过注解方式进行配置,具体大家可以…

Boost::asio io_service 实现分析

io_service的作用 io_servie 实现了一个任务队列&#xff0c;这里的任务就是void(void)的函数。Io_servie最常用的两个接口是post和run&#xff0c;post向任务队列中投递任务&#xff0c;run是执行队列中的任务&#xff0c;直到全部执行完毕&#xff0c;并且run可以被N个线程调…

叮!你有一份2018英特尔人工智能大会的邀请函,请查收!

AI赋能的数字化应用&#xff0c;作为时代发展的核心驱动力&#xff0c;已经成为改变各行各业的神奇力量。想要准确把握智能时代的发展航向&#xff0c;领航舵手英特尔已向你发出邀请&#xff1a;2018英特尔人工智能大会&#xff0c;欢迎你的到来&#xff01;11月14日-15日&…

赢得高薪的锦囊三秘诀

作者&#xff1a;jingch 来源&#xff1a;南京竞成 时间&#xff1a;2007-6-27 10:58:40 秘诀一 获得高薪的必备素质通过对一些高收入的外企白领阶层的调查发现&#xff0c;高学历并不与高收入划等号&#xff0c;高薪收入者的基本素质上的优势才是他们获得高薪的关键。概括起…

可疑文件_【国家标准】印刷文件鉴定技术规范点阵式打印文件的同机鉴定

印刷文件鉴定技术规范(GB/T 37232-2018)总则印刷文件同机(同版)鉴定的受理程序、送检材料的标识、检验鉴定程序、送检材料的流转程序及结果报告程序应按GB/T 37234-2018第4章~第8章中相应的要求。印刷文件同机鉴定分为传统制版文件同机鉴定和办公设备机制文件同机鉴定。其中,办…

前端开发神器之ngrok

ngrok能做什么&#xff0c;为什么是前端开发神器&#xff1f; 内网穿透&#xff0c;映射本地开发环境到公网&#xff0c;模拟多终端线上环境。 结合一个很简单的PWA demo&#xff0c;举个简单的例子 1.克隆demo到本地 git clone https://github.com/minimal-xyz/minimal-pwa.gi…

YC陆奇发起知乎第一问:怎样的环境才能让更多AI创业公司成功?

“在人工智能时代&#xff0c;怎样的创新环境和措施能让更多科技驱动的创业公司成功&#xff0c;使其不再是大型科技公司的专利&#xff1f;” 一周前&#xff0c;知乎发起了“2018 互联网洞见者”提问&#xff0c;先后邀请到鹅厂厂长马化腾、“风投女王”徐新、香港科技大学杨…

Linq to SQL 资源

Scott Guthrie 的 Linq to SQL 系列&#xff1a;1)介绍http://weblogs.asp.net/scottgu/archive/2007/05/19/using-linq-to-sql-part-1.aspx 2)定义数据模型http://weblogs.asp.net/scottgu/archive/2007/05/29/linq-to-sql-part-2-defining-our-data-model-classes.aspx 3)查询…

首发|机器学习未来十年:你需要把握的趋势和热点

CSDN 出品的《2018-2019 中国人工智能产业路线图》V2.0 版即将重磅面世&#xff01; V1.0 版发布以来&#xff0c;我们有幸得到了诸多读者朋友及行业专家的鼎力支持&#xff0c;在此表示由衷感谢。此次 V2.0 版路线图将进行新一轮大升级&#xff0c;力求为读者呈现更全面的中国…

web前端知识点太多_初学web前端,学习方法容易走偏,这是为什么?

一、了解web前端所谓“知己知彼&#xff0c;百战不殆”&#xff0c;在学习web前端之前&#xff0c;还是让我们先了解一下什么是web前端吧&#xff01;所有用户终端产品与视觉和交互有关的部分&#xff0c;都属于前端开发的领域。从狭义上讲&#xff0c;Web前端就是用HTML、CSS、…

2017-2018 ACM-ICPC, NEERC, Southern Subregional Contest

A. Automatic Door 对于规律的点可以推公式计算&#xff0c;对于噪点则暴力计算&#xff0c;时间复杂度$O(m\log m)$。 #include<stdio.h> #include<iostream> #include<string.h> #include<string> #include<ctype.h> #include<math.h> #…

正则过滤非法字符

小写英文&#xff1a;大写英文&#xff1a;任意数字&#xff1a;限2位小数&#xff1a; 如: 123.12日  期&#xff1a; 如: 2002-9-29任意中文&#xff1a;部分英文&#xff1a; 范围: a,b,c,d,e部分中文&#xff1a; 范围: 一二三四五六七八九十有关正则表达式 ?.只能输入数…

emoji 乱码_这个自制emoji的网站,让你成为永远不输的斗图王者

作为表情界的元老级人物&#xff0c;不管是苹果官网输入法、微信官方表情还是各个主流输入法里&#xff0c;我们都可以从里面找到大量 emoji 表情。然鹅……就算这么多表情&#xff0c;小帮每次发 emoji 时还有有些选择困难。因为翻遍所有表情&#xff0c;都没法找到合适的啊&a…

[vijos1234]口袋的天空最小生成树

题目链接&#xff1a;https://vijos.org/p/1234 白天刚刚写完prim的算法&#xff0c;晚上就心血来潮的打了一道最小生成树的题 虽然有题解说可以用prim做&#xff0c;但是这道题明显是加最小的边&#xff0c;感觉kruskal方便多了 但是愉快的是我竟然不是一次过&#xff0c;最后…

南开大学提出最新边缘检测与图像分割算法,精度刷新记录(附开源地址)

作者 | 刘云、程明明、胡晓伟、边佳旺等 译者 | 刘畅 整理 | Jane 出品 | AI科技大本营 近日&#xff0c;南开大学媒体计算实验室提出的最新边缘检测和图像过分割&#xff08;可用于生成超像素&#xff09;被 IEEE PAMI 录用。研究的第一作者也发微博称&#xff1a;“这是第…

修改Vista系统目录权限

例如C:\Windows\System32\DriverStore\FileRepository1. 修改目录所有者右键菜单->Properties->Security->Advanced->Owner->Edit->Other users or groups...输入用户名并确定&#xff0c;勾选Replace owner on subcontainers and objects&#xff0c;一路确…

gitlab安装各种坑

架构&#xff1a;源码安装, 数据库用mysql,网站用nginx 坑一.nginx报错 122016/07/19 09:26:11 [crit] 3881#0: *10 connect() to unix:/home/git/gitlab/tmp/sockets/gitlab-workhorse.socket failed (13: Permission denied) while connecting to upstream, client: 192.168.…

当代的设计潮流是什么_解码“潮流合伙人”IP生意经

每经记者&#xff1a;杜蔚 每经编辑&#xff1a;董兴生11月18日&#xff0c;备受期待的《潮流合伙人2》在成都举办了FOURTRY FAMILY PARTY新品发布日活动&#xff0c;节目的品牌主理人陈伟霆&#xff0c;合伙人欧阳娜娜、范丞丞等纷纷亮相现场&#xff0c;吸引众多人前来围观。…

Loonframwork到SWT的移植测试(JAVA GAME TEST SOURCE)

愚以为&#xff0c;用SWT作界面&#xff0c;是一种在用Java写VB的体验。本周心情极度恶劣&#xff0c;一直不想说话&#xff0c;也不想写新代码&#xff0c;郁闷中尝试了一下将Loonframework的代码移植到SWT。&#xff08;其实我觉得AWT,SWT,Swing用那个真的要根据需求决定&…

百度大脑发挥AI“头雁效应” 王海峰:在AI时代共同推动社会智能化升级

11月1日&#xff0c;百度大脑作为2018百度世界大会的第一弹登场。 近期国家层面也高度重视人工智能的发展现状和趋势&#xff0c;认为加快发展新一代人工智能是事关我国能否抓住新一轮科技革命和产业变革机遇的战略问题。人工智能技术具有溢出带动性很强的“头雁”效应。百度高…

bat脚本如何自动输入y_Linux系统如何设置开机自动运行脚本?

大家好&#xff0c;我是良许。 在工作中&#xff0c;我们经常有个需求&#xff0c;那就是在系统启动之后&#xff0c;自动启动某个脚本或服务。在 Windows 下&#xff0c;我们有很多方法可以设置开机启动&#xff0c;但在 Linux 系统下我们需要如何操作呢&#xff1f; Linux 下…

form表单的action提交写到js中来,同时onclick事件也写在js中来。其action也可以通过ajax来提交的。...

假如你现在还在为自己的技术担忧&#xff0c;假如你现在想提升自己的工资&#xff0c;假如你想在职场上获得更多的话语权&#xff0c;假如你想顺利的度过35岁这个魔咒&#xff0c;假如你想体验BAT的工作环境&#xff0c;那么现在请我们一起开启提升技术之旅吧&#xff0c;详情请…

Win32.Lioten.SG病毒

病毒名称&#xff1a;Win32.Lioten.SG 疯狂性&#xff1a;低 破坏性&#xff1a;中 普及度&#xff1a;中 Win32.Lioten.SG病毒描述&#xff1a; Win32.Lioten.SG是一种通过网络共享传播的蠕虫&#xff0c;还会利用Windows漏洞进行传播&#xff0c;并利用IRC控制后门。 Lioten经…

2019秋招AI岗位竞争究竟有多激烈?

机器学习未来十年&#xff1a;你需要把握的趋势和热点一个正经的机器学习项目&#xff1a;关于那些羞羞的不可描述的动作分析【面试现场】如何编程获得最多的年终红包奖&#xff1f;你最关心的马蜂窝事件舆论全景图在这里&#xff0c;用文本挖掘一挖到底影响 5000 万开发者&…

配置Tomcat和在Eclipse中创建Web工程

配置Tomcat服务器信息&#xff1a;在Tomcat的安装目录下有一个conf目录&#xff0c;里面存放着Tomcat服务器的配置文件&#xff0c;其中最为核心的配置文件是server.xml&#xff0c;在这个文件里我们可以配置服务器的各种参数&#xff0c;例如超时时间、连接数量、端口配置等等…

eureka需要替换吗_iOS第三方库Eureka实现定制动画详解(二):万变不离其宗-Row组件...

Eureka的核心就是Row&#xff0c;所以我们得重点聊聊它。Row是什么&#xff1f;其实上面已经说过了&#xff0c;不过这只是干巴巴的概念&#xff0c;下面本猫用一个实际的例子带大家性感&#xff0c;哦&#xff0c;不…是感性的认识一下到底什么是Row 新建一个iOS项目&#xff…

学习这么多算法到底在解决哪些问题?深度学习之外,我们要选择谁?

CSDN 出品的《2018-2019 中国人工智能产业路线图》V2.0 版即将重磅面世&#xff01; V1.0 版发布以来&#xff0c;我们有幸得到了诸多读者朋友及行业专家的鼎力支持&#xff0c;在此表示由衷感谢。此次 V2.0 版路线图将进行新一轮大升级&#xff0c;力求为读者呈现更全面的中国…

JDK6.0+Eclipse3.2+MyEclipse5.0GA+Tomcat5.0+Win2003搭建J2EE开发平台.

呼.........不容易啊.J2EE平台今天终于搭建起来了.... 1.先安装jdk-6-beta2-windows-i586.exe,安装目录:E:\Program Files\Java\jdk1.6.0 2.然后安装jakarta-tomcat-5.0.30服务器.安装目录:E:\Program Files\Java\Tomcat 5.0 3.在"我的电脑"--"属性"--&quo…

Google全球员工围攻Google!

参加 2018 AI开发者大会&#xff0c;请点击 ↑↑↑屋漏偏逢连夜雨&#xff0c;仍未进得了中国的搜索巨人 Google&#xff0c;在自己的地盘上&#xff0c;日子也不好过。自 2005 年收购以来&#xff0c;硅谷科技巨头 Google 在世界上第一大手机操作系统 Android 收益颇丰&#x…