- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
当我编译这段C#代码时(full text)并运行 ArrayTest.exe ,进程挂起几秒钟,消耗 1 GB RAM,并因 StackOverflowException 而崩溃。为什么?
public struct Point { }
public class ArrayTest {
public static void Main(string[] args) {
Point[][] array = {
new Point[]{new Point(), new Point(), /* ... 296 omitted ... */, new Point(), new Point()},
new Point[]{new Point(), new Point(), /* ... 296 omitted ... */, new Point(), new Point()},
/* ... 296 omitted ... */
new Point[]{new Point(), new Point(), /* ... 296 omitted ... */, new Point(), new Point()},
new Point[]{new Point(), new Point(), /* ... 296 omitted ... */, new Point(), new Point()},
};
/* Do nothing and return */
}
}
我正在为 Microsoft (R) .NET Framework 4.5 使用 Microsoft (R) Visual C# 编译器版本 4.0.30319.33440。我只是在命令行上调用 csc.exe 并执行编译后的 EXE。当我添加 csc /optimize
标志时,问题就消失了。上面的代码片段确实是我正在测试的完整代码 - 在初始化数组后,Main() 中没有执行任何有用的工作。
问题背景:我试图将一组数字测试用例硬编码到一个程序中。在 Java、JavaScript 或 Python 中,代码看起来像这样并且可以正常工作:
class Point { int x; int y; }
Point[][] data = { // About 1000 entries
{new Point(1, 2)},
{new Point(5, 3), new Point(0, 6), new Point(1, 8)}, // Different length
... et cetera ...
};
for (Point[] thing : data):
test(thing);
但是当我尝试在 C# 中编译这样的代码时,数组初始化花费了很长的时间(~5 秒),甚至在使用 test()
的 for 循环开始之前执行。
我的实际代码已经缩减为上面的 MVCE,其中 struct Point
不包含任何字段,而 Main()
仅包含数组初始化,没有任何有用的工作。
最佳答案
好的,我开始编译你的类文件的调试/发布版本。使用 14.0 版工具中的 VS 2015 编译器,IL 的输出是相同的。这涵盖了人们没有注意到问题的原因。
在 VS 2013 中使用的先前编译器中的调试与发布非常直接。 Debug模式下的可执行文件输出为 2,091 kb。发行版中的 IL 表明它只是忽略实际对象,因为它从未被使用过。好的。我会将 VS 2015 Debug IL 与 VS 2013 Debug IL 进行比较。
为简洁起见,我已将数组大小更改为 3x3。
这是 2015 IL 的输出:
.method public hidebysig static void Main() cil managed
{
.entrypoint
// Code size 45 (0x2d)
.maxstack 4
.locals init (valuetype Point[][] V_0)
IL_0000: nop
IL_0001: ldc.i4.4
IL_0002: newarr valuetype Point[]
IL_0007: dup
IL_0008: ldc.i4.0
IL_0009: ldc.i4.3
IL_000a: newarr Point
IL_000f: stelem.ref
IL_0010: dup
IL_0011: ldc.i4.1
IL_0012: ldc.i4.3
IL_0013: newarr Point
IL_0018: stelem.ref
IL_0019: dup
IL_001a: ldc.i4.2
IL_001b: ldc.i4.3
IL_001c: newarr Point
IL_0021: stelem.ref
IL_0022: dup
IL_0023: ldc.i4.3
IL_0024: ldc.i4.3
IL_0025: newarr Point
IL_002a: stelem.ref
IL_002b: stloc.0
IL_002c: ret
} // end of method ArrayTest::Main
此代码与 Release模式代码之间的主要区别是额外的 nop 指令。
这是 2012/2013 版编译器的输出:
.method public hidebysig static void Main() cil managed
{
.entrypoint
// Code size 307 (0x133)
.maxstack 4
.locals init (valuetype Point[][] V_0,
valuetype Point[][] V_1,
valuetype Point[] V_2,
valuetype Point V_3)
IL_0000: nop
IL_0001: ldc.i4.4
IL_0002: newarr valuetype Point[]
IL_0007: stloc.1
IL_0008: ldloc.1
IL_0009: ldc.i4.0
IL_000a: ldc.i4.3
IL_000b: newarr Point
IL_0010: stloc.2
IL_0011: ldloc.2
IL_0012: ldc.i4.0
IL_0013: ldelema Point
IL_0018: ldloca.s V_3
IL_001a: initobj Point
IL_0020: ldloc.3
IL_0021: stobj Point
IL_0026: ldloc.2
IL_0027: ldc.i4.1
IL_0028: ldelema Point
IL_002d: ldloca.s V_3
IL_002f: initobj Point
IL_0035: ldloc.3
IL_0036: stobj Point
IL_003b: ldloc.2
IL_003c: ldc.i4.2
IL_003d: ldelema Point
IL_0042: ldloca.s V_3
IL_0044: initobj Point
IL_004a: ldloc.3
IL_004b: stobj Point
IL_0050: ldloc.2
IL_0051: stelem.ref
IL_0052: ldloc.1
IL_0053: ldc.i4.1
IL_0054: ldc.i4.3
IL_0055: newarr Point
IL_005a: stloc.2
IL_005b: ldloc.2
IL_005c: ldc.i4.0
IL_005d: ldelema Point
IL_0062: ldloca.s V_3
IL_0064: initobj Point
IL_006a: ldloc.3
IL_006b: stobj Point
IL_0070: ldloc.2
IL_0071: ldc.i4.1
IL_0072: ldelema Point
IL_0077: ldloca.s V_3
IL_0079: initobj Point
IL_007f: ldloc.3
IL_0080: stobj Point
IL_0085: ldloc.2
IL_0086: ldc.i4.2
IL_0087: ldelema Point
IL_008c: ldloca.s V_3
IL_008e: initobj Point
IL_0094: ldloc.3
IL_0095: stobj Point
IL_009a: ldloc.2
IL_009b: stelem.ref
IL_009c: ldloc.1
IL_009d: ldc.i4.2
IL_009e: ldc.i4.3
IL_009f: newarr Point
IL_00a4: stloc.2
IL_00a5: ldloc.2
IL_00a6: ldc.i4.0
IL_00a7: ldelema Point
IL_00ac: ldloca.s V_3
IL_00ae: initobj Point
IL_00b4: ldloc.3
IL_00b5: stobj Point
IL_00ba: ldloc.2
IL_00bb: ldc.i4.1
IL_00bc: ldelema Point
IL_00c1: ldloca.s V_3
IL_00c3: initobj Point
IL_00c9: ldloc.3
IL_00ca: stobj Point
IL_00cf: ldloc.2
IL_00d0: ldc.i4.2
IL_00d1: ldelema Point
IL_00d6: ldloca.s V_3
IL_00d8: initobj Point
IL_00de: ldloc.3
IL_00df: stobj Point
IL_00e4: ldloc.2
IL_00e5: stelem.ref
IL_00e6: ldloc.1
IL_00e7: ldc.i4.3
IL_00e8: ldc.i4.3
IL_00e9: newarr Point
IL_00ee: stloc.2
IL_00ef: ldloc.2
IL_00f0: ldc.i4.0
IL_00f1: ldelema Point
IL_00f6: ldloca.s V_3
IL_00f8: initobj Point
IL_00fe: ldloc.3
IL_00ff: stobj Point
IL_0104: ldloc.2
IL_0105: ldc.i4.1
IL_0106: ldelema Point
IL_010b: ldloca.s V_3
IL_010d: initobj Point
IL_0113: ldloc.3
IL_0114: stobj Point
IL_0119: ldloc.2
IL_011a: ldc.i4.2
IL_011b: ldelema Point
IL_0120: ldloca.s V_3
IL_0122: initobj Point
IL_0128: ldloc.3
IL_0129: stobj Point
IL_012e: ldloc.2
IL_012f: stelem.ref
IL_0130: ldloc.1
IL_0131: stloc.0
IL_0132: ret
} // end of method ArrayTest::Main
因此,在您使用的 2012/2013 编译器中, Debug模式进行了大量的堆栈分配,可能是为了让您可以在编辑期间智能感知整个锯齿状数组结构并继续,或者可能这样您可能进入每个单独的对象构造。我对此完全不确定。
我不是 IL 方面的专家,但在我看来,它正在为每个点分配,然后为每个数组再次分配,然后再次为锯齿状数组分配,导致分配过多。
关于c# - 初始化大型锯齿状数组会占用超过 1 GB 的 RAM 并因 StackOverflowException 而崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39583023/
dataElementsList : TypesAndData.DataElement list 是一个包含 50,000 条记录的列表(实际上更多,但让我们从小处开始)。我正在尝试序列化为 JSON
我试图序列化一个自定义类型,该类型在其他成员中包含一个字典。与字典的键和值相关联的类型是实现的接口(interface)。 字典看起来像 Dictionary TypeA implements IT
我有一个 C# 工厂对象,它使用对象列表作为源,通过工厂方法创建对象。 对象列表的创建方式如下: public WidgetFactory() { widgetLibrary
我正在 GenericList 类中实现递归快速排序方法。我将有第二种方法,它接受一个compareDelegate来比较不同的类型,但出于开发目的,我对GenericList进行排序。 我根据列表大
我为我的作业编写了一种方法,用于通过递归计算整数数组的所有排列。 (我正在尝试实现回溯算法)。但计算超过 7 个数字的前突变时会导致 StackOverflowException 。我不知道如何解决这
我正在尝试将一个大文件拆分成许多小文件。每个拆分发生的位置基于检查每个给定行的内容返回的谓词(isNextObject 函数)。 我试图通过 File.ReadLines 函数读取大文件,这样我就可以
我正在使用 onSuccessCallBack() 接口(interface)方法同步大量数据。按照如图所示的方法将数据发送到服务器。在这里我面临 StackOverflowException 的问题
我必须递归调用一个函数。但片刻之后它会抛出 StackOverFlowException。当我使用 Invoke(new Action(Start)) 方法时,它会抛出相同的异常,但不会在很长一段时间
我有一些依赖于 HttpContext.Cache 的代码,我希望它在满足特定条件时重新缓存某些内容。但是,这会引入潜在的堆栈溢出,我不确定这里的适当方法是什么。 看看这段代码: void OnCac
我将我的代码剥离到导致问题的部分。代码在这里来回跳转第5行和第9行,导致stackoverflowexception。 我该如何做呢?我需要 Game 类中的 Platform 实例才能在函数中使用。
我的问题很简单。我有这个新表格,我只是编写代码: public partial class Form1 : Form { public Form1() { In
根据我的question (通用方法的可重用非通用方法)我已经实现了提供的解决方案,但经过一些重构(将代码移动到基类)后,我的代码导致了我不理解的 StackOverflowException。 调用
背景。我的脚本在递归搜索大字符串中的特定文本时遇到 StackOverflowException。循环不是无限的;问题发生在 9,000-10,000 次合法搜索之间(对于特定搜索)——我需要它继续进
请帮助我解决 System.StackOverflowException我想用 .aspx 将记录写入数据库我使用 4 层架构来实现这一切都正常但是当我编译页面然后它显示要插入数据的字段时,当我将数据
我正在尝试回答 my own old question基于我唯一的(无效的)答案。 这个想法是为了简化按值排序的映射的创建: public class SortedByValueMap> implem
我目前正在制作有界数组堆栈。此方法将大于存储容量的数组抛出到 StackOverflowException,除了我不断收到“throws StackOverflowException 部分”的错误消息
我正在使用以下方法递归迭代对象的属性: void GetProps(object obj) { if (obj == null) return; var objType
我想做一个非常简单的任务,它以某种方式使程序崩溃。 我有一个包含数字的列表,所有数字都是唯一的。超过一定数量,我想倒序。 示例:5, 16, 11, 3, 8, 4 -> 5, 16, 11, 4,
我正在尝试编写一个函数来检查字符串是否为回文,并使用 this example ,我正在尝试使用递归匿名函数反转字符串: static Boolean checkPalindromeAnonRec(s
这段代码有什么问题?我不断收到 StackOverlflowException.. public class Places { public string Title { get; set;
我是一名优秀的程序员,十分优秀!