java - 理论上 'structs' 的数组在 Java 中是可行的吗?

标签 java memory jvm memory-efficient

在某些情况下,需要一种高效的内存来存储大量对象。要在 Java 中做到这一点,您不得不使用几个原始数组(请参阅下面的原因)或一个大字节数组,这会产生一些 CPU 开销以进行转换。

例子:你有一个 class Point { float x; float y;。现在您想将 N 个点存储在一个数组中,在 32 位 JVM 上,该数组至少需要 N * 8 个字节用于 float ,N * 4 个字节用于引用。所以至少有 1/3 是垃圾(这里不计算普通对象开销)。但是,如果您将其存储在两个 float 组中,一切都会很好。

我的问题:为什么 Java 不优化引用数组的内存使用?我的意思是为什么不像在 C++ 中那样直接将对象嵌入数组中?

例如将类 Point 标记为 final 应该足以让 JVM 看到 Point 类数据的最大长度。或者这是反对the specification的地方?此外,在处理大型 n 维矩阵等时,这将节省大量内存

更新:

我想知道 JVM 是否可以在理论上优化它(例如在幕后)以及在什么条件下 - 而不是我是否可以以某种方式强制 JVM。我认为结论的第二点是无法轻易完成的原因。

JVM 需要知道的结论:

  1. 该类需要是 final 以便 JVM 猜测一个数组条目的长度
  2. 数组需要是只读的。当然,您可以更改值,例如 Point p = arr[i]; p.setX(i) 但您不能通过 inlineArr[i] = new Point() 写入数组。或者 JVM 将不得不引入与“Java 方式”相反的复制语义。查看 aroth 的回答
  3. 如何初始化数组(调用默认构造函数或将成员初始化为其默认值)

最佳答案

Java 不提供执行此操作的方法,因为它不是语言级别的选择。 C、C++ 等公开了执行此操作的方法,因为它们是系统级编程语言,您需要了解系统级功能并根据您使用的特定架构做出决策。

在 Java 中,您的目标是 JVM。 JVM 没有指定这是否允许(我假设这是真的;我没有彻底梳理 JLS 来证明我在这里)。这个想法是,当您编写 Java 代码时,您相信 JIT 会做出明智的决定。这就是引用类型可以折叠成数组等的地方。因此,这里的“Java 方式”是您无法指定它是否发生,但如果 JIT 可以进行优化并提高性能,它就可以而且应该这样做。

我不确定这个优化是否具体实现了,但我知道类似的是:例如,用 new 分配的对象在概念上是在“堆”上,但是如果 JVM注意到(通过一种称为逃逸分析的技术)对象是方法局部的,它可以在堆栈上甚至直接在 CPU 寄存器中分配对象的字段,完全消除“堆分配”开销而无需更改语言。

更新问题的更新

如果问题是“这完全可以做到”,我认为答案是肯定的。有一些极端情况(例如空指针),但您应该能够解决它们。对于空引用,JVM 可以说服自己永远不会有空元素,或者如前所述保留一个位 vector 。这两种技术都可能基于逃逸分析,表明数组引用永远不会离开方法,因为我可以看到,如果你尝试,例如,簿记会变得棘手。将其存储在对象字段中。

关于java - 理论上 'structs' 的数组在 Java 中是可行的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9387055/

相关文章:

Python:对子字符串列表进行排序,而不创建每个子字符串的单独副本

c++ - 比 boost::file_mapping 更快的读取文件的方法?

reflection - kotlin反射获取字段列表

java - Kotlin 委托(delegate)属性实现 'provideDelegate' 运算符函数,但从未调用方法

java - Oracle JDK8:展开循环由JVM转换为NOOP吗?

java - Android - 使用带有 adRquest 的 admob 加载广告时遇到问题

java - 检查给定的对象是否是通用的并得到否。参数个数

java - EmptyResultDataAccessException 作为运行时异常

java - web.xml 中的 url-pattern 问题

memory - 多级页表如何节省内存空间?