我有一个小型只读数据库(基于来自服务的数据)。加载时间至关重要,因此无法从DB,XML等中提取数据。我在生成的C#文件中使用数据的直接构造:
void Load(){
var aa = new A[ 100500 ];
aa[0] = new A( ... );
...
aa[100499] = new A( ... );
AA = aa;
}
这里没有递归,堆栈锁等。但是我遇到了StackOverflow错误。
在反汇编器窗口中,我发现JIT将此代码转换为:
var aa = new A[ 100500 ];
var a0 = new A( ... );
aa[0] = a0;
...
var a100499 = new A( ... );
aa[100499] = a100499;
因此它在堆栈中创建了100500个变量aXXXXX:
-- aa[32] = new A( qwerty, asdf );
mov ecx,185C10h -- var a32 = new A
call 001730F4
mov dword ptr [ebp-4Ch],eax -- different for different rows
push dword ptr ds:[4403528h] -- a32.ctor( ... )
mov edx,dword ptr ds:[4403524h]
mov ecx,dword ptr [ebp-4Ch]
call 00790068
push dword ptr [ebp-4Ch] -- aa[32] = a32
mov ecx,dword ptr [ebp-3Ch]
mov edx,20h
call 71CCCD30
这些更改无济于事:
// 1. explicit variable
A a;
a = new A( ... ); // a32 = new A(...); a = a32;
aa[32] = a
// 2. limited visibility
{ aa[32] = new A( ... ); } // for each created object
此更改有帮助,但太难看了:
// Works in Release version only
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static void f32( A[] aa )
=> aa[32] = new A( qwerty, asdf );
...
f32( aa ); -- inlined without a32
移除这些吞噬者有什么优雅的方法吗?
提前感谢。
coreclr存储库中存在未解决的问题,尚未解决:https://github.com/dotnet/coreclr/issues/14103。它于2017年开放,因此似乎不太可能很快修复它。 JIT编译器中存在一个问题,因为IL代码看起来不错(IL有其自己的堆栈,并且可以重用堆栈中的变量)。
为了保留美观的代码,我可以推荐2种方法:
Load_000000_001000
,Load_001000_002000
,...,然后从Load
调用它们。