V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
61162833
V2EX  ›  Java

Java 中一个保存了 1 万个整数的 ArrayList 占多少内存?

  •  
  •   61162833 · 167 天前 · 4065 次点击
    这是一个创建于 167 天前的主题,其中的信息可能已经有所发展或是发生改变。
    代码:
    List<Integer> ints=new ArrayList();
    for(int i=0;i<10000;i++){
    ints.add(i);
    }

    gpt-3.5 的回答:
    在 64 位的 Java 虚拟机中,一个空的 ArrayList 对象通常占用 24 字节。
    在 Java 中,一个 Integer 对象通常占用 16 字节(在 32 位和 64 位的 Java 虚拟机中都是如此)。

    在 64 位的 Java 虚拟机中:
    ArrayList 对象本身:24 字节
    整数对象:16 字节 × 10000 = 160000 字节
    总内存占用:24 字节 + 160000 字节 = 160024 字节

    也就是说,一个仅保存了 1 万个整数的 ArrayList 就要占 160KB 服务器内存?
    一个保存了 10 万个整数的 ArrayList 就要占 1.6MB 内存?

    怎么与实际感觉似乎不太相符,
    有能用 gpt 4.0 的富哥问下这答案对吗?

    另外,ArrayList 中保存的整数占内存数与数字大小有关系吗?(比如保存 1 万个 1 亿+的数字,与保存 1-10000 有区别吗?)
    16 条回复    2023-11-13 11:19:37 +08:00
    cubecube
        1
    cubecube  
       167 天前   ❤️ 1
    gpt 回答是正确的
    和数字大小没关系,int 最大 21 亿
    yfugibr
        2
    yfugibr  
       167 天前 via Android   ❤️ 1
    不止,ArrayList 的空间分配不是要多少就分配多少,而是在容量填满后扩充到之前的大约 1.5 倍(可以去看具体实现),你存 a 个对象,但它分配的空间可能多达 1.5a 个
    61162833
        3
    61162833  
    OP
       167 天前
    @cubecube 谢谢,这么一算感觉内存很不经用啊,保存几十万个数字就要爆了
    61162833
        4
    61162833  
    OP
       167 天前
    @yfugibr 就是保存 100 个数字要占 150 个数字的内存空间?
    rabbbit
        5
    rabbbit  
       167 天前   ❤️ 1
    ArrayList 可以设定初始容量值,避免自动扩容。
    int 占 4 字节
    嫌多还有 short 2 字节 byte 1 字节
    humpy
        6
    humpy  
       167 天前   ❤️ 4
    可以用 [JOL]( https://github.com/openjdk/jol) 工具测一下:

    System.out.println(GraphLayout.parseInstance(ints).toFootprint());

    ---

    java.util.ArrayList@5679c6c6d footprint:
    COUNT AVG SUM DESCRIPTION
    1 40016 40016 [Ljava.lang.Object;
    10000 16 160000 java.lang.Integer
    1 24 24 java.util.ArrayList
    10002 200040 (total)

    在我的机器上( 64 位 JDK8 ),大约 200040 / 1024 = 195kb
    yeqizhang
        7
    yeqizhang  
       167 天前 via Android   ❤️ 1
    没啥不相符合的,首先高并发的项目,出现大集合的情况少,其次集群下,单台机的业务并发也不会太高,有高并发的业务都堆机器堆内存去了。
    还有就是,只要变成垃圾变的快,jvm 回收了也没啥压力。
    yfugibr
        8
    yfugibr  
       167 天前   ❤️ 1
    @61162833 #4 不是这个意思,ArrayList 底层存储是数组,有一个初始容量(不确定是多少),会在数组被填满时建一个新数组替换旧数组来扩充容量,新数组的容量大约是之前的 1.5 倍(取决于具体实现),直到新数组再次被填满时再次扩容,所以多数情况下都是有空间“浪费”的,但是浪费了多少要看你的存入的容量和 ArrayList 的实现。

    当然你也可以直接指定 ArrayList 的容量,这部分就自行搜索吧。
    mazyi
        9
    mazyi  
       167 天前 via iPhone
    这有啥不经用的,你可以去看看 python 的,和 js 的,让你对编程语言有全新认识
    ruxuan1306
        10
    ruxuan1306  
       167 天前
    @yfugibr 自动扩容是在 append 时原容量不够才发生的,new 时候给定大小,然后直接用下标设置就不会触发扩容。
    winglight2016
        11
    winglight2016  
       167 天前
    lz 如果觉得内存很容易不够用,可以去看看微机原理这本书,或者了解一下 linux 内核的内存寻址相关内容。

    jvm32 位的时候,最大内存只有 1.5G ,的确很容易爆,但是 64 位已经支持到超过硬盘容量了,更大数量的并行计算(如果不需要并行,那限制只是时间问题)已经转变成了分布式计算的问题,而不是高效利用内存——这和 AI 的发展趋势相似,注意力放在了解决通用问题。
    junkun
        12
    junkun  
       166 天前   ❤️ 1
    补充一下,如果要省内存可以用 int[]数组,或者自己用数组封装一个 int 类型的线性表。主要是因为 Java 泛型只能支持封装类型的元素,所以占用空间不理想。然而基本类型的数组除了头以外,内部是连续存储的。
    lancelee01
        13
    lancelee01  
       166 天前
    10 万个整数,1.6MB 说实话不大啊。再优化也就是把 List 改成数组,数组本身占用 16 字节,节省 8 字节,整数 int 4 字节,累计 16 + 4 * 100000 ,相当于减少一半
    zhouhu
        14
    zhouhu  
       166 天前
    @junkun 是的,很多开源的集合库可以用。比如 eclipse collection 。
    Aresxue
        15
    Aresxue  
       166 天前
    所以有了 fastutil 这个库。。话说 java 自己的 Valhalla 项目正在做泛型特化以后你就可以用 List<int>了。
    zhouhu
        16
    zhouhu  
       166 天前
    还可以开启指针压缩
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2804 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 06:10 · PVG 14:10 · LAX 23:10 · JFK 02:10
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.