- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在某种同行评审期间调试一些 C# 代码时,我注意到一种奇怪的行为,乍一看似乎是某种范围界定违规,但回想起来,编译器可能试图通过重用引用来节省内存。代码是:
for(int i = 0; i < 10; i++)
{
// Yadda yadda, something happens here
}
// At this point, i is out of scope and is not
// accessible. This is verified by intellisense
// and by attempting to look at the variable
// during debug
string whatever = "";
// At this point if I put a break on the following
// for line, I can look at the variable I before
// it is initialized and see that it already holds
// the value of 10. If a different variable name
// is used, I get a value of 0 (not initialized).
for(int i = 0; i < 10; i++)
{
// Inside the loop, i has been re-initialized
// so it performs its function as expected
}
编译器是否简单地重用了现有的引用?在需要更紧密地管理变量/引用的 C/C++ 中,这是我期望的行为。对于 C#,我的印象是每次在循环范围内声明一个变量时,它都会划分出一个新的单独的内存部分,但显然情况并非如此。这是一种内存节省功能,可能是 C/C++ 行为的延续,还是这种情况只是被忽略,因为编译器无论如何都会强制您重新初始化?
编辑:
我在做一些其他检查时注意到的一些事情是,这种行为不会在类中的方法之间表现出来。它确实出现在多个
using
语句中,但仅当类型和名称相同时才会出现。
经过进一步调查,我开始相信这与其说是关于 MISL 代码,不如说是关于将这些引用保留在自己的内存中的 IDE。我没有看到任何迹象表明这种行为实际上会存在于代码级别,所以现在我倾向于认为这只是 IDE 的一个怪癖。
编辑 2:
看起来 @Vijay Gill 的回答反驳了 IDE 的怪癖。
最佳答案
这完全取决于编译器以及您用于编译的配置。在下面的文本转储中,您可以看到在 Release 模式下,声明了两个 int 变量,而在 dubug 模式下,只有一个。
为什么会这样完全超出我的理解(暂时我回家再调查)
编辑:在这个答案的末尾查看更多发现
private static void f1()
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("Loop 1");
}
Console.WriteLine("Interval");
for (int i = 0; i < 10; i++)
{
Console.WriteLine("Loop 2");
}
}
发布方式:(注意局部变量i & V_1)
.method private hidebysig static void f1() cil managed
{
// Code size 57 (0x39)
.maxstack 2
.locals init ([0] int32 i,
[1] int32 V_1)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: br.s IL_0012
IL_0004: ldstr "Loop 1"
IL_0009: call void [mscorlib]System.Console::WriteLine(string)
IL_000e: ldloc.0
IL_000f: ldc.i4.1
IL_0010: add
IL_0011: stloc.0
IL_0012: ldloc.0
IL_0013: ldc.i4.s 10
IL_0015: blt.s IL_0004
IL_0017: ldstr "Interval"
IL_001c: call void [mscorlib]System.Console::WriteLine(string)
IL_0021: ldc.i4.0
IL_0022: stloc.1
IL_0023: br.s IL_0033
IL_0025: ldstr "Loop 2"
IL_002a: call void [mscorlib]System.Console::WriteLine(string)
IL_002f: ldloc.1
IL_0030: ldc.i4.1
IL_0031: add
IL_0032: stloc.1
IL_0033: ldloc.1
IL_0034: ldc.i4.s 10
IL_0036: blt.s IL_0025
IL_0038: ret
} // end of method Program::f1
Debug模式:(注意局部变量i)
.method private hidebysig static void f1() cil managed
{
// Code size 73 (0x49)
.maxstack 2
.locals init ([0] int32 i,
[1] bool CS$4$0000)
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: br.s IL_0016
IL_0005: nop
IL_0006: ldstr "Loop 1"
IL_000b: call void [mscorlib]System.Console::WriteLine(string)
IL_0010: nop
IL_0011: nop
IL_0012: ldloc.0
IL_0013: ldc.i4.1
IL_0014: add
IL_0015: stloc.0
IL_0016: ldloc.0
IL_0017: ldc.i4.s 10
IL_0019: clt
IL_001b: stloc.1
IL_001c: ldloc.1
IL_001d: brtrue.s IL_0005
IL_001f: ldstr "Interval"
IL_0024: call void [mscorlib]System.Console::WriteLine(string)
IL_0029: nop
IL_002a: ldc.i4.0
IL_002b: stloc.0
IL_002c: br.s IL_003f
IL_002e: nop
IL_002f: ldstr "Loop 2"
IL_0034: call void [mscorlib]System.Console::WriteLine(string)
IL_0039: nop
IL_003a: nop
IL_003b: ldloc.0
IL_003c: ldc.i4.1
IL_003d: add
IL_003e: stloc.0
IL_003f: ldloc.0
IL_0040: ldc.i4.s 10
IL_0042: clt
IL_0044: stloc.1
IL_0045: ldloc.1
IL_0046: brtrue.s IL_002e
IL_0048: ret
} // end of method Program::f1
生成的汇编代码如下。这仅适用于在 Release模式下编译的 IL。现在,即使在机器语言中(此处已反汇编),我也看到创建了两个局部变量。我找不到任何答案。只有 MS 家伙可以告诉我们。但是当我们编写与堆栈使用相关的递归方法时,记住这种行为非常重要。
00000000 push ebp
00000001 mov ebp,esp
00000003 sub esp,0Ch
00000006 mov dword ptr [ebp-4],ecx
00000009 cmp dword ptr ds:[04471B50h],0
00000010 je 00000017
00000012 call 763A4647
-- initialisation of local variables
-- this is why we get all ints set to zero initially (will see similar behavioir for other types too)
00000017 xor edx,edx
00000019 mov dword ptr [ebp-8],edx
0000001c xor edx,edx
0000001e mov dword ptr [ebp-0Ch],edx
00000021 xor edx,edx -- zero out register edx which will be saved to memory where i (first one) is located
00000023 mov dword ptr [ebp-8],edx -- initialise variable i (first one) with 0
00000026 nop
00000027 jmp 00000037 -- jump to the loop condition
00000029 mov ecx,dword ptr ds:[01B32088h]
0000002f call 76A84E7C -- calls method to print the message "Loop 1"
00000034 inc dword ptr [ebp-8] -- increment i (first one) by 1
00000037 cmp dword ptr [ebp-8],0Ah -- compare with 10
0000003b jl 00000029 -- if still less, go to address 00000029
0000003d mov ecx,dword ptr ds:[01B3208Ch]
00000043 call 76A84E7C -- prints the message "Half way there"
00000048 xor edx,edx -- zero out register edx which will be saved to memory where i (second one) is located
0000004a mov dword ptr [ebp-0Ch],edx -- initialise i (second one) with 0
0000004d nop
0000004e jmp 0000005E -- jump to the loop condition
00000050 mov ecx,dword ptr ds:[01B32090h]
00000056 call 76A84E7C -- calls method to print the message "Loop 1"
0000005b inc dword ptr [ebp-0Ch] -- increment i (second one) by 1
0000005e cmp dword ptr [ebp-0Ch],0Ah -- compare with 10
00000062 jl 00000050 -- if still less, go to address 00000050
00000064 nop
00000065 mov esp,ebp
00000067 pop ebp
00000068 ret
关于c# - MSIL 代码中的变量作用域/重用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6830172/
将已完成的 MPI_Request 重新用于另一个请求是否安全?我一直在使用 MPI_Request 池来提高性能并且没有错误。但肯定知道会很好。 最佳答案 MPI_Request 类型的变量不是请求
我注意到 Qt 文档在翻译的某些方面不是很冗长。我一直在玩弄它,试图通过反复试验来弄清楚他们的行为。最终目标是在运行时更改翻译,但我很困惑 QTranslator 对象在多大程度上可以重用。 考虑一下
我有一个 UIImageView 对象,它只是一个纯黑色矩形。这是我用来选择 View 中的按钮的方法。 问题是,我的 View 中有 49 个这样的按钮,并且所有这些按钮都可以同时选择。 我用来向按
在 R 中构建模型时,如何保存模型规范以便可以在新数据上重用它?假设我根据历史数据建立逻辑回归,但直到下个月才会有新的观察结果。最好的方法是什么? 我考虑过的事情: 保存模型对象并在新 session
我是 React/Redux 的初学者。 我已经完成了一个基本组件在我的应用程序中,其操作/ reducer /商店运行良好。 我将渲染另一个 具有不同的设置( Prop )。 我想做的是分离这两个组
我正在开发 GUI 纸牌游戏,我想知道是否有办法改进我的代码。这是我的情况。 我有三张牌:A、B 和 C。玩家可以通过分别单击三个按钮之一来更换牌:分别是按钮 1、按钮 2 或按钮 3。 class
每个文本框旁边有 2 个文本框和 2 个按钮 [...]。是否可以使用一个 OpenFileDialog 并将 FilePath 传递到相应的文本框,基于单击哪个按钮?即...如果我单击第一个按钮并打
我有两个场景:第一个场景,渲染纹理平面,第二个场景,应该渲染为纹理。该纹理应用作主场景中平面的贴图。 出于某种原因,所有 THREE.WebGLRenderTarget 示例每帧都会重新绘制两个场景,
我知道 concat、StringBuffer 和 StringBuilder 之间的区别。我知道 StringBuffer.toString 支持数组的内存问题可能会导致内存爆炸。我什至知道 JDK
我有 2 个 Activity 。 A 和 B。A 有一个包含 4 个项目的操作栏。每个项目显示不同的电影列表。 B extends A 因为我希望能够使用操作栏来更改电影列表。 所以我的问题是,当我
我有一个查询,用于检查从搜索文本框中输入的每个关键字,并且必须返回最匹配的关键字。 问题是,我想排除返回行中所有值为 0 的 KW_MATCHED。 SELECT A1.*, (
当方法重用时,是否有像这样的代码可以与 UICollectionViewCell 一起使用? - (UITableViewCell *)tableView:(UITableView *)tableVi
在我的项目中,我想在可 ScrollView 中以zig-zag 模式显示图像。所以我使用 uiscrollview 子查看其中的图像。它工作正常,但它占用了太多内存,因为我将所有图像加载到 Scro
如果我有 UIViewController1 并且我让它以模态方式显示 UIViewController2,但我希望 UIViewController2 显示 UIViewController1 模式
我想在所有 CCMenuItem 中使用完全相同的标签。如果我创建相同的 CCLabelTTF 一次,那么我无法将其添加到多个 CCMenuItem 中,因为它会给出有关已添加标签的运行时错误。但是,
我正在做一个项目,我们需要显示列表与用户位置的距离。为了显示距离,当在输入中给出纬度/经度时,我们使用名为“distance”的脚本字段计算距离 "script_fields" : {
我正在尝试重用我的 UITableViewCells。目前我的应用程序运行良好,在 tableView 中显示内容。然而,当我尝试实现 - 重用 UITableViewCells 时,我的应用程序崩溃
假设我在外部样式表中定义了几个类 .b {font-weight:bold;} .c {text-align:center;} 现在我想要另一个类,它是 b 和 c 的组合 .bc 是否可以使用类 b
我目前经常分配新的协程实例(请参阅我的回答中的代码 here)。 这样做的开销并不小。 我猜想是否有某种方法可以通过重用之前分配的协程来降低成本? 虽然不确定如何实现这一点? 我可以为协程 Alloc
在我的应用程序中,我使用如下代码下载多张图片。这样做是高性能还是我可以以某种方式重用连接? for(int i = 0; i < 100; i++){ URL url = new UR
我是一名优秀的程序员,十分优秀!