代码之家  ›  专栏  ›  技术社区  ›  James McMahon

在托管代码中,如何实现良好的引用位置?

  •  10
  • James McMahon  · 技术社区  · 15 年前

    因为Ram似乎 the new disk ,而且由于该语句还意味着对内存的访问现在被认为是缓慢的,这与磁盘访问一直以来的速度类似,因此我确实希望为高性能应用程序最大化内存中的引用位置。例如,在已排序的索引中,我希望相邻值接近(与哈希表中的值不同),并且我也希望索引指向的数据也接近。

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

    不过,我想,即使在这种高度抽象的情况下,也有一些东西可以在语义上被认为是“更接近”的,因此很可能是 事实上 在低水平更近。例如,我想知道以下内容(我在括号中的猜测):

    • 我能期望数组是相邻的内存块吗(是)?
    • 同一实例中的两个整数是否比同一类(可能)的不同实例中的两个整数更接近?
    • 一个物体是否占据了记忆中的一个挫伤区域(不)?
    • 只有两个的对象数组有什么区别 int 两个字段和一个对象 int[] 领域?(这个例子可能是Java特有的)

    我开始在Java环境中思考这些问题,但是我的疑惑已经变得更普遍了,所以我建议不要把它当作一个Java问题来对待。

    6 回复  |  直到 15 年前
        1
  •  9
  •   Jon Skeet    15 年前
    • 在.NET中,数组元素肯定是连续的。在Java中,我希望它们在大多数实现中,但似乎不能保证。
    • 我认为这是合理的 假定 实例用于字段的内存在单个块中…但不要忘记,其中一些字段可能是对其他对象的引用。

    对于Java数组部分, Sun's JNI documentation 包括这个评论,隐藏在关于字符串的讨论中:

    例如,Java虚拟机可能不会连续存储数组。

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

    我相信,在Java和.NET中,如果在一个线程中快速连续地分配许多小对象,那么这些对象就是 可能的 具有良好的参考位置。当GC压缩一个堆时,这可能会改善——或者如果一个具有

    A B C D E
    

    被压缩到

    A D E B
    

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

    基本上,在托管环境中,您对引用位置的控制通常不如在非托管环境中那样多——您必须相信托管环境足够擅长管理它,并且您将通过编码到更高级别的平台来节省足够的时间,从而使您可以花时间在其他地方进行优化。

        2
  •  3
  •   JesperE    15 年前

    首先,你的头衔是“C”。“托管代码”是微软创造的一个术语,如果我没有弄错的话。

    Java原始数组保证是一个连续的内存块。如果你有

    int[] array = new int[4];
    

    你可以从JNI(原生C)获得 int *p 指向实际数组。我认为这也适用于容器的array*类(arrayList、arrayBlockingQueue等)。

    我认为,JVM的早期实现将对象作为连续结构,但这不能用新的JVM来假设。(JNI把这个抽象掉了)。

    同一对象中的两个整数可能如您所说“更接近”,但它们可能不是。即使使用相同的JVM,这也可能有所不同。

    有两个int字段的对象是一个对象,我认为任何JVM都不能保证成员是“关闭”的。一个包含两个元素的int数组很可能由一个8字节长的数组作为后盾。

        3
  •  2
  •   Dzmitry Huba    15 年前

    关于数组,这里是来自cli(公共语言基础结构)规范的摘录:

    应布置阵列元件。 在行major中的数组对象中 顺序(即相关元素 最右边的数组维度 从最低到最高的索引应连续排列。 )。这个 实际存储分配给每个 数组元素可以包括 平台特定的填充。(尺寸) 返回此存储的字节数 按sizeof指令 应用于该数组的类型 元素。

        4
  •  2
  •   Kylotan    15 年前

    好问题!我想我会求助于C++中的扩展,它以更仔细的管理方式处理内存,并且仅仅暴露足够的接口,以允许应用程序的其余部分操作对象。如果我关心性能,我可能会求助于C++扩展。

        5
  •  2
  •   Nick Craig-Wood    15 年前

    我想没人谈论过蟒蛇,所以我想试试看。

    我能期望数组是相邻的内存块吗(是)?

    在Python中,数组更像C中的指针数组。因此指针将是相邻的,但实际对象不太可能是。

    同一实例中的两个整数是否比同一类(可能)的不同实例中的两个整数更接近?

    可能与上述原因不同。实例将只保存指向实际整数的对象的指针。Python没有原生int(像Java),只有boxed Int(在Java语言中)。

    一个物体是否占据了记忆中的一个挫伤区域(不)?

    大概不会。但是,如果您使用 __slots__ 优化,那么它的一些部分将是连续的!

    一个只有两个int字段的对象数组和一个只有两个int[]字段的对象数组有什么区别? (这个例子可能是Java特有的)

    在Python中,就内存位置而言,它们几乎是相同的!一个将生成指向对象的指针数组,对象将依次包含指向整数的两个指针,另一个将生成指向整数的两个指针数组。

        6
  •  -3
  •   wefwfwefwe    15 年前

    如果您需要优化到这个水平,那么我怀疑基于虚拟机的语言不适合您;)