Dav*_*e S 8 c# clr struct memory-management prefetch
出于好奇,我试图测试List<T>
使用两者value
和reference
类型的性能.
结果并不像我预期的那样,让我相信我对这些对象在内存中如何布局的理解可能不正确.
这是我的实验:
创建一个class
只包含两个成员的基本,a int
和abool
创建2个List<T>
对象来保存我的测试类(List1
和List2
)
随机生成的测试对象并将其添加到List1
和List2
交替
时间迭代需要多长时间List1
(执行一些任意工作,例如递增计数器然后访问元素)
然后我重复了一个struct
代替class
我的假设是,当使用a时class
,其中的引用List<T>
将是连续的,但由于我如何创建它们(在添加到List1
和之间切换List2
),它们指向的对象可能不会.
我认为当使用a时struct
,因为它是一个值类型,所以对象本身将在内存中连续List<T>
保持(因为它保存实际的项而不是引用的集合).
因此,我期望struct
表现更好(由于预取器等...)
实际上,两者都非常相似.
这里发生了什么?
编辑 - 添加了实际访问迭代器中元素的代码,包括代码示例
测试类(或结构)
public class/struct TestClass
{
public int TestInt;
public bool TestBool;
}
Run Code Online (Sandbox Code Playgroud)
创建随机列表:
var list1 = new List<TestClass>();
var list2 = new List<TestClass>();
var toggle = false;
for (var i=0; i < 4000000; i++)
{
// Random object generation removed for simplicity
if (toggle)
list1.Add(randomObject);
else
list2.Add(randomObject);
toggle = !toggle;
}
Run Code Online (Sandbox Code Playgroud)
测试:
var stopWatch = new Stopwatch();
var counter = 0;
var testBool = false;
stopwatch.Start();
foreach(var item in list1)
{
// Access the element
testBool = item.TestBool;
counter++;
}
stopwatch.Stop();
Run Code Online (Sandbox Code Playgroud)
同时重复TestObject
a class
和a struct
.
我意识到没有太大的区别,但我希望struct
表现得更好class
Han*_*ant 10
// Access the element
testBool = item.TestBool;
Run Code Online (Sandbox Code Playgroud)
这没有效果,优化器将删除该语句,因为它没有有用的副作用.您实际上并没有测量结构和类之间的差异,因为您实际上从未实际访问该元素.
counter++;
Run Code Online (Sandbox Code Playgroud)
同样的故事,很可能会被优化掉.除非您实际使用计数器值,否则在循环完成后.让优化器删除太多代码并使测试无意义是一个常见的微基准危险.解决方法是:
foreach(var item in list1)
{
// Access the element
counter += item.TestInt;
}
Console.WriteLine(counter);
Run Code Online (Sandbox Code Playgroud)
基准指南是:
如果您实际上没有访问列表中存储的类对象的成员,那么以下两种类型应该为迭代提供相同的性能.
List<IntPtr>
List<object>
即使引用类型实例没有填充连续的内存部分,引用本身也是如此.
上述情况的例外情况是,如果CLR在执行内存小于32GiB的64位应用程序时压缩指针.此策略记录为JVM中的压缩OOPS.但是,x86-64指令集包含的指令允许非常有效地执行此压缩/解压缩,因此即使在这种情况下,您也应该看到类似的性能List<int>
.
当值类型超过指针(IntPtr.Size
)的大小时,事情变得有趣.在此之后,List<T>
包含引用的性能应该快速超过List<T>
值类型的性能.这是因为无论您的引用类型实例有多大,对该实例的引用最多IntPtr.Size
.
归档时间: |
|
查看次数: |
3083 次 |
最近记录: |