Java 在存储和内存方面为浮点型或双精度型

Java 在存储和内存方面为浮点型或双精度型,java,memory,double,heap,Java,Memory,Double,Heap,我正在解析精度不是我主要关心的数据。即使使用最大java堆大小,我也经常会得到java.lang.OutOfMemoryError。所以我主要关心的是内存使用和java堆空间。我应该使用double还是float数据类型?如果您的内存使用与大量(数百万)浮点数有关(可以通过一个合适的内存分析器进行验证),那么您很可能将它们存储在一些数据结构中,如数组或列表 建议(我想,你已经遵循了其中的大部分…) 如果数字范围和精度足够,则首选float而不是double,因为这只消耗一半的大小 不要使用ja

我正在解析精度不是我主要关心的数据。即使使用最大java堆大小,我也经常会得到java.lang.OutOfMemoryError。所以我主要关心的是内存使用和java堆空间。我应该使用double还是float数据类型?

如果您的内存使用与大量(数百万)浮点数有关(可以通过一个合适的内存分析器进行验证),那么您很可能将它们存储在一些数据结构中,如数组或列表

建议(我想,你已经遵循了其中的大部分…)

  • 如果数字范围和精度足够,则首选
    float
    而不是
    double
    ,因为这只消耗一半的大小
  • 不要使用
    java.lang.Float
    java.lang.Double
    类进行存储,因为与裸标量值相比,它们有相当大的内存开销
  • 请确保使用数组,而不是像
    java.util.List
    这样的集合,因为它们存储装箱的
    java.lang.Float
    实例,而不是裸数字
但除此之外,有一个像样的内存分析器可以告诉您哪些实例占用了大部分内存。除了浮点/双精度数据,可能还有其他内存消费者

编辑:


OP最近的评论“我一直得到OOM异常,因为我使用了大量带有数字的ArrayList”,这一点很清楚<与
float[]
相比,code>ArrayList浪费了大量内存(Stephen C在他的回答中给出了详细的数字),但它提供了动态调整大小的好处

因此,我看到以下可能性:

  • 如果可以从一开始就知道数组大小,那么立即使用
    float[]
    arrays
  • 如果在初始化实例时需要动态大小,请在构建一个对象时使用
    ArrayList
    (当大小仍然增加时),然后将内容复制到
    float[]
    数组中进行长期存储。那么浪费的数组列表只存在有限的时间跨度
  • 如果在数据的整个生命周期内需要动态大小,请基于
    float[]
    数组创建自己的
    floataraylist
    类,就像
    ArrayList
    一样,只要代码需要(可以是非常浅层的实现,也可以是全功能的列表,可能基于
    AbstractList

我总是得到OOM异常,因为我使用了大量带有数字的ArrayList

那是你的问题

  • N个32位浮点值的
    ArrayList
    在32位JVM中至少需要120*N字节,在64位JVM2中至少需要24*N字节

  • N个64位浮点值的
    ArrayList
    占用的空间量与相同

  • 以上仅说明支持数组和列表元素。如果有大量小的
    ArrayList
    对象,则
    ArrayList
    对象本身的开销可能很大。(为每个
    ArrayList
    object`添加16或24个字节。)

  • 如果使用动态调整大小,这可能会随着备份阵列的增长而产生对象搅动。在某些情况下,支持阵列可能是其需要的两倍大

相比之下:

  • 32位浮点值数组大约需要4*N字节4

  • 一个64位浮点值数组大约需要8*N字节4

  • 动态调整大小不会造成浪费

解决方案:

  • ArrayList
    ArrayList
    没有区别。这不是一个解决办法

  • 为了最大限度地节省,根据您的精度要求,使用
    float[]
    double[]
    。预先分配阵列以容纳所需的确切数量的元素

  • 如果您想要动态调整大小的灵活性,有第三方库可以实现节省空间的基本类型列表。或者实现您自己的。但是,您将无法使用标准的
    List
    API,因为这会迫使您使用
    Float
    Double


  • 1-实际使用的空间取决于
    ArrayList
    的创建和填充方式。如果您预先分配了一个容量完全正确的
    ArrayList
    ,您将使用上面提到的空间。如果通过使用默认初始容量重复添加到
    ArrayList
    来构建阵列,则32位JVM将平均使用N*2字节的额外空间。这是由于
    ArrayList
    用于在备份数组已满时增加备份数组的启发式方法造成的

    2-在64位JVM上,指针占用8字节而不是4字节。。。除非您使用的是压缩OOP

    3-占用相同字节数的原因是,在典型的JVM上,由于堆节点填充,a
    Float
    和a
    Double
    都是16个字节


    4-每个数组的头开销(通常)为12字节,数组的堆节点大小被填充为8字节的倍数

    您必须增加堆大小,但您在做什么,以获得一致的OOM异常?与byte和short的建议一样,如果需要在浮点数的大数组中保存内存,请使用浮点(而不是双精度浮点),浮点占用4个字节,双精度浮点占用8个字节的存储空间。因此,根据您的使用情况/数据大小,答案应该是显而易见的。但是,您到底想做什么,以及如何设置堆大小?你能提供更多的信息吗?如果精度不是您主要关心的问题,那么您应该使用浮点、long、int、short、byte或bit。在某个时候,它将成为你主要关心的问题。只有你知道那一点在哪里,我一直都知道