【问题标题】:Java - How can I create a variable with the required size in Java?Java - 如何在 Java 中创建具有所需大小的变量?
【发布时间】:2016-01-06 06:11:15
【问题描述】:

考虑这种情况。我的程序中有一千个int 变量。我们知道一个int变量在Java中占用了2个字节的内存空间。因此,我的变量占用的空间总量为 2000 字节。但是,问题在于,每个变量中的值只占用了它所拥有的空间的一半。因此,实际需要的空间是 1000 字节,这意味着 1000 字节被浪费了。我该如何解决这个问题?有没有办法在 Java 中解决这个问题?

【问题讨论】:

  • We know that an int variable occupies 2 bytes of memory space in Java. 我知道不会:)
  • 另外,您在这里要解决的原始问题是什么? (不是您认为的解决方案,而是潜在的计算问题。)
  • 你能解释清楚一点吗@biziclop? :-)
  • 时间与空间。有一些集合可以让您调整后者。这取决于你想做什么。提防过早的优化。
  • @KonakanchiSaketh 好的,那不一样了。一般来说,您应该合理地调整数据字段的大小:不要使用longs 来存储月份中的某天,但同时也不要使用byte 来存储温度,因为很可能会发生某些事情太热或太冷。除此之外,还有可变大小的数据结构,但它们是有代价的:它们通常有一个固定的标题,它本身占用空间(这使得它们对于少量数据不切实际)。

标签: java performance memory


【解决方案1】:

您的数据适合一个字节,因此只需使用 byte 而不是 int(即 4 个字节)。

【讨论】:

  • 作为旁注,使用 int 占用 4000 字节 = 4KB。这真的是一个问题吗,因为它似乎是一个可以忽略不计的内存量。
  • AFAIK 大多数 JVM 也使用 32 位的 byte 类型。
  • @fabian 个人,是的。但是多个字节字段(或字节数组)可以是packed
【解决方案2】:

每次存储值时检查它们所需的空间将意味着产生额外的无用开销。

如果您知道您的值的大小,那么您可以在开发时正确选择它们的类型。如果您不知道您的值可能占用多少空间,则必须选择尽可能大的空间。

在运行期间,例如,如果一个值是 int,这意味着它可能介于 -2^31 和 (2^31)-1 之间。如果你知道这个值永远不会是这个大小,你可以使用更小的原语,例如byteshort

我们可以检查并分配内存中每个元素所需的确切内存量,但这需要更多时间。相反,使用固定数量的内存显然占用更多空间但速度更快,这就是Java的工作原理。不幸的是,我们不能不妥协。

【讨论】:

  • 是的,真正的兄弟。最终判决说,“我们不能不妥协……” :-)
【解决方案3】:
  1. Java 中的 int 长度为 32 位(4 字节)
  2. int 中保存的值不会影响内存中的 int 大小,例如如果您的 int 的值为 0x55

所以,要占用2000字节的内存,就需要500个int,如果创建一个int数组,就会有数组本身的开销,所以会占用更多的内存。

【讨论】:

    【解决方案4】:
    1. int 数据类型是 32 位有符号二进制补码整数。 因此占用了 4 个字节的内存。 对于int
      • 最小值为 - 2,147,483,648.(-2^31)
      • 最大值为2,147,483,647(含)。(2^31 -1)

    如果您的值不会太大,那么您可以根据需要使用byteshort

    1. Byte 数据类型是一个 8 位有符号二进制补码整数。

      • 最小值为 -128 (-2^7)
      • 最大值为127(含)(2^7 -1)
    2. Short 数据类型是一个 16 位有符号二进制补码整数。

      • 最小值为 -32,768 (-2^15)
      • 最大值为 32,767(含)(2^15 -1)

    如果您真的不确定大型列表中有多少元素,您也可以使用linked list

    与传统数组相比,链表的主要优点是可以轻松插入或删除列表元素,而无需重新分配或重组整个结构,因为数据项不需要连续存储在内存或磁盘中,而在编译和运行程序之前,必须在源代码中声明数组。链表允许在链表中的任何点插入和删除节点,如果在链表遍历期间保持在被添加或删除的链接之前的链接,则可以通过恒定数量的操作来完成。

    通常为int 数据类型或更重的数据类型使用链表,因为它们实际上会导致每个元素的开销至少为 1 个指针大小,因此如果您的元素很小,实际上情况会更糟。

    【讨论】:

    • 但是值得一提的是,链表也会产生至少 1 个指针大小的每个元素的开销,所以如果你的元素很小,实际上你的情况会更糟。
    • 重点应该放在元素大小上。双向链表每个元素将花费您 8/16 字节,因此如果您的元素是 byte,您将浪费 90-95% 的空间。但是,如果您的元素是 8 kbyte 缓冲区,则开销仅为 0.1-0.2%,无论列表大小如何。
    • 如果您使用 byte[],这将只使用大约 1 KB(1000 个字节),如果您使用 ArrayList<Byte>,则每个条目将使用大约 4 个字节或 4 KB,如果您使用LinkedList 每个元素将使用大约 24 个字节。
    • 更新了我的答案。感谢 biziclop 和@Peter Lawrey 提供的宝贵见解
    【解决方案5】:

    Oracle docs

    int: 默认情况下,int 数据类型是 32 位有符号二进制补码 整数

    也就是说int在内存中占用了4个字节。

    字节:字节数据类型是一个8位有符号二进制补码整数

    因此,在您的情况下,您可以将数据类型更改为 byte 而不是 int。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-03-21
      • 2015-06-19
      • 1970-01-01
      • 1970-01-01
      • 2022-11-22
      • 2017-07-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多