C# · 12月 29, 2021

c# – 在托管代码中,如何获得良好的参考位置?

由于RAM似乎是 the new disk,并且由于该声明也意味着访问内存现在被认为类似于磁盘访问一直很慢,所以我希望最大限度地提高内存中对于高性能应用程序的引用.例如,在排序索引中,我希望相邻的值是接近的(不像在散列表中),我想要索引指向的附加数据.

在C中,我可以用一个专门的内存管理器来创建一个数据结构,就像这个(非常复杂的)Judy array的开发者一样.通过对指针的直接控制,它们甚至可以在指针值本身编码附加信息.在Python,Java或C#中工作时,我故意从这种类型的解决方案中抽象出一个(或更多)的抽象级别,并且委托JIT编译器和优化运行时,在我的低级别上做出巧妙的技巧.

尽管如此,即使在这个高抽象层面上,也有一些可以被语义上认为“更接近”的东西,因此可能在较低层次上实际上更接近.例如,我想知道以下(我的括号中的猜测):

>我可以期望一个数组是相邻的内存块(是)吗?
>在相同的实例中,两个整数在同一个类的不同实例中可能比两个更接近(可能)?
>对象是否占用内存中的肮脏区域(否)?
>只有两个int字段的对象数组和具有两个int []字段的单个对象之间有什么区别? (这个例子可能是Java具体的)

我开始在Java环境中想到这些,但我的想法已经变得更加普遍了,所以我建议不要把它当作Java的问题.

解决方法 >在.NET中,数组的元素当然是连续的.在Java中,我期望他们在大多数实现中,但似乎不能保证.
>我认为可以合理的假设一个实例为字段使用的内存在一个单独的块…但不要忘记,这些字段中的一些可能是对其他对象的引用.

对于Java数组部分,Sun’s JNI documentation包含了这个评论,在关于字符串的讨论中,

For example,the Java virtual machine may not store arrays contiguously.

对于你的最后一个问题,如果你有两个int [],那么这些数组中的每个都将是一个连续的内存块,但它们在内存中可能非常“远”.如果您有一个包含两个int字段的对象数组,那么每个对象可能会有很长的距离,但每个对象中的两个整数将会相互靠近.可能更重要的是,由于每个对象的开销,您将最终获得“许多对象”解决方案的更多内存.在.NET中,您可以使用具有两个整数的自定义结构体,并具有一组数组,这些数组将所有数据保存在一个大块中.

我相信,在Java和.NET中,如果您在单个线程中快速连续分配大量小对象,那么这些对象可能具有良好的参考位置.当GC压缩一个堆时,这可能会改善 – 或者它可能会变得更糟,如果一个堆

A B C D E

被压实到

A D E B

(C被收集) – 突然之间可能已经“接近”的A和B距离很远.我不知道这是否真的发生在任何垃圾收集器(有负载在周围!),但它是可能的.

在一个受管理的环境中,您通常不会像在非管理环境中一样掌握参考的位置 – 您必须相信管理环境对管理环境有足够的好处,而且您将节省足够的时间通过编码到更高级别的平台,让您花时间优化其他地方.