【问题标题】:Java ArrayList<primitive datatype> consecutive memory allocation only for references?Java ArrayList<primitive datatype> 连续内存分配仅用于引用?
【发布时间】:2013-08-23 07:23:30
【问题描述】:

我想分配一个原始数据类型对象的数组列表,如 int、char 等(不是数组,因为它将来会增长可能不是线性的),但需要存储在 RAM 中的连续内存位置(jvm 托管堆)。但是自从我为 ex 的原始数据类型声明 ArrayList 时。 ArrayList 为 int,内部 jvm 映射到 ArrayList 类型的对象。
现在的问题是 ArrayList 持有对存储在 jvm 管理的内存空间中不同位置的对象的连续引用。但我最初的想法是连续存储实际数据对象而不仅仅是参考!但我不知道如何实现它?

我能想到的一个解决方案是分配大尺寸字节数组,从而创建一个连续的内存缓冲存储!如果有 1000 个 int 对象存储在 2000 个预分配字节中,开发人员需要管理如何在 101 个索引位置获取一些存储在这个手动创建的缓冲区(假设我们建模为 2 个字节/int)中的 int 数据!



复杂数据类型也需要相同的功能。虽然在处理复杂对象的连续内存分配时可能会很困难,因为需要计算结构大小并预分配 (structureSize * No. of Elements Expected) 的字节缓冲区



对于连续分配对象(原始/复杂>),我想不出任何其他有效的方法或解决方案。谁能帮助我?

【问题讨论】:

  • 您正在尝试解决一个不存在的问题。为什么您认为当前的 Java 内存模型效率低下,而您可以做得更好?
  • 宝藏是我想检查的东西!谢谢:)

标签: java arraylist jvm bytebuffer primitive-types


【解决方案1】:

没有单一的解决方案可以满足您的要求。

如果您想要一个原始类型的类数组结构,那么您需要使用该原始类型的数组或包装该原始类型数组的某个类1。如果您尝试实现自定义类,则它不能是泛型的(在原始类型上),因为原始类型不能用作泛型类型参数。因此,它不能是ArrayList 或从Collection 派生的任何其他类型。

如果您想要一个引用类型的类数组结构,那么您可以使用数组或ArrayList


简而言之,如果您不愿意使用包装器类型(Integer 等):

  • 您必须分别处理原始类型和非原始类型。
  • 最好(从 API 设计和类型安全的角度)分别处理各个原始类型。

假设,您可以创建一个类数组类型,该类型实现任何原始类型的数组,具体取决于运行时参数。只需定义许多方法/重载来获取/设置不同的原始类型。但是,这不是编译时类型安全的,而且 API 会 ...至少可以这么说。

您使用ByteBuffer 的想法与上述基本相同......或者更糟的是,如果您预计应用程序代码会在字节和名义上的“数组”基本类型之间执行所有索引和编码/解码。 (你最好从byte[] 开始而不是ByteBuffer。)


1 - 例如,Trove 集合类之一。

【讨论】:

  • 字节数组指向在 ByteBuffer 之前开始。但是,当您考虑连续存储非原始类型时,Array 和 ArrayList 都能够存储对位于内存中随机位置的对象的连续引用。然后在这种情况下预分配 no 字节数组是有意义的。要存储的复杂对象的数量乘以一个此类对象的大小。
【解决方案2】:

免责声明:无论如何都没有指定,因此可能会有机会。

在 OpenJDK/Oracle JVM 中,对象在 TLAB 中按顺序分配。一旦它被复制到幸存者/终身空间中,它就会以相反的顺序被发现。这意味着这些对象很可能一起在缓存中。

一个简单的解决方案是使用基于图元的集合,例如 Trove,其中图元实际上位于图元数组中。

【讨论】:

    【解决方案3】:

    有很多原始集合项目,这里是其中的一些:

    1. org.apache.commons.collections.primitives
    2. High Performance Primitive Collections
    3. Trove

    但是请注意,使用这些东西,您会越来越难以实施。没有通用的原始集合 API。

    【讨论】:

      【解决方案4】:

      由于内存碎片问题,您正在尝试做的事情在技术上是不可能的。想想看。如果您的缓冲区需要增长,它需要重新分配整个内存量,这会连续地快速分割内存,即使您在技术上拥有足够的内存,也会让您的内存不足。在常规 java 中最接近的可能是 java.nio.IntBuffer。但正如其他人所说,您正在尝试解决一个不存在的问题。

      【讨论】:

      • 是的,是的,但我从应用程序的角度考虑更多,例如为列存储数据库实施存储方案,如果连续存储单个列项,则在计算聚合时将获得巨大的性能提升。如果 cpu 知道无论列大小有多大,所有列数据都是按顺序存储的,那么计算下一个元组地址的操作周期就被消除了。这同样适用于行存储数据库,您可能需要顺序非原始存储类型才能获得此类收益。我希望我能够传达它。
      • 如果这种低级“优化”对您很重要,那么您可能一开始就不应该使用 Java。
      • 好吧,现在看来 Java 并没有为低级优化提供这种灵活性?
      • Java 中的优化通常侧重于 VM,而不是字节码,其理念是因为 JIT 编译器知道它在哪个平台和架构上运行和/或编写,所以在更好的优化位置。这是一次写入/随处运行范例的一部分。如果您只想在固定平台(例如 Windows/x64)上运行应用程序,Java 提供了 JNI 机制,允许您进行特定于平台的低级优化。
      • 好的..我将检查 JNI。谢谢米克尔:)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-29
      • 2012-07-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多