在 Java 中,使用 List<Map<泛型类型, 泛型类型>> 存储 100 万个对象和使用 List<对象类型> 存储 100 万个对象,通常情况下 List<Map<泛型类型, 泛型类型>> 占用的空间更大。下面详细分析原因:

内存占用情况分析

1. List<对象类型> 存储方式

当使用 List<对象类型> 存储对象时,List 本身会维护一个内部数组来存储这些对象的引用。每个对象会在堆内存中占据一定的空间,而 List 只需要存储这些对象的引用。

import java.util.ArrayList;
import java.util.List;

class MyObject {
    private int id;
    private String name;

    public MyObject(int id, String name) {
        this.id = id;
        this.name = name;
    }
}

public class ListObjectExample {
    public static void main(String[] args) {
        List<MyObject> list = new ArrayList<>();
        for (int i = 0; i < 1000000; i++) {
            list.add(new MyObject(i, "Name" + i));
        }
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.

在这个例子中,List 只需要存储 100 万个 MyObject 对象的引用,而每个 MyObject 对象包含一个 int 类型的 id 和一个 String 类型的 name

2. List<Map<泛型类型, 泛型类型>> 存储方式

当使用 List<Map<泛型类型, 泛型类型>> 存储对象时,List 同样会维护一个内部数组来存储 Map 对象的引用。而每个 Map 对象本身也需要占用一定的内存空间,并且 Map 内部会存储键值对,每个键值对也会占用额外的内存。

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ListMapExample {
    public static void main(String[] args) {
        List<Map<String, Object>> list = new ArrayList<>();
        for (int i = 0; i < 1000000; i++) {
            Map<String, Object> map = new HashMap<>();
            map.put("id", i);
            map.put("name", "Name" + i);
            list.add(map);
        }
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

在这个例子中,List 需要存储 100 万个 Map 对象的引用,每个 Map 对象内部又存储了键值对,除了存储与 MyObject 相同的数据外,Map 本身还有额外的开销,例如哈希表的数组、链表节点等。

占用空间大的原因总结

  • 额外的数据结构开销Map 是一种复杂的数据结构,为了实现高效的查找、插入和删除操作,Map 内部使用了哈希表等数据结构,这些数据结构需要额外的内存空间来存储。例如,HashMap 内部会维护一个数组和链表(或红黑树)来解决哈希冲突,这些都会增加内存占用。
  • 键值对的包装开销:在 Map 中,每个键值对都需要封装成一个 Entry 对象,这也会增加额外的内存开销。

测试类

public class MemoryUsageTest {

    // 定义一个简单的对象类
    static class MyObject {
        private int id;
        private String name;

        public MyObject(int id, String name) {
            this.id = id;
            this.name = name;
        }
    }

    // 计算 List<对象类型> 存储方式的内存占用
    public static long testListOfObjects() {
        // 获取当前 JVM 的可用内存
        Runtime runtime = Runtime.getRuntime();
        long beforeMemory = runtime.totalMemory() - runtime.freeMemory();

        // 创建 100 万个 MyObject 对象并存储在 List 中
        List<MyObject> list = new ArrayList<>();
        for (int i = 0; i < 1000000; i++) {
            list.add(new MyObject(i, "Name" + i));
        }

        // 获取创建对象后的 JVM 可用内存
        long afterMemory = runtime.totalMemory() - runtime.freeMemory();
        // 计算内存占用
        return afterMemory - beforeMemory;
    }

    // 计算 List<Map<泛型类型, 泛型类型>> 存储方式的内存占用
    public static long testListOfMaps() {
        // 获取当前 JVM 的可用内存
        Runtime runtime = Runtime.getRuntime();
        long beforeMemory = runtime.totalMemory() - runtime.freeMemory();

        // 创建 100 万个 Map 对象并存储在 List 中
        List<Map<String, Object>> list = new ArrayList<>();
        for (int i = 0; i < 1000000; i++) {
            Map<String, Object> map = new HashMap<>();
            map.put("id", i);
            map.put("name", "Name" + i);
            list.add(map);
        }

        // 获取创建对象后的 JVM 可用内存
        long afterMemory = runtime.totalMemory() - runtime.freeMemory();
        // 计算内存占用
        return afterMemory - beforeMemory;
    }

    public static void main(String[] args) {
        // 测试 List<对象类型> 的内存占用
        long listOfObjectsMemory = testListOfObjects();
        System.out.println("List<MyObject> 占用的内存: " + listOfObjectsMemory / 1024 / 1024 + " MB");

        // 测试 List<Map<泛型类型, 泛型类型>> 的内存占用
        long listOfMapsMemory = testListOfMaps();
        System.out.println("List<Map<String, Object>> 占用的内存: " + listOfMapsMemory / 1024 / 1024 + "  MB");

        // 比较两种存储方式的内存占用
        if (listOfMapsMemory > listOfObjectsMemory) {
            System.out.println("List<Map<String, Object>> 占用的内存更大。");
        } else if (listOfMapsMemory < listOfObjectsMemory) {
            System.out.println("List<MyObject> 占用的内存更大。");
        } else {
            System.out.println("两种存储方式占用的内存相同。");
        }
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
运行结果

100万个对象运行3次的结果

第一次

Java中有100万个对象,用list map泛型存储和用list对象泛型存储,那个占用空间大,为什么_集合

第二次

Java中有100万个对象,用list map泛型存储和用list对象泛型存储,那个占用空间大,为什么_存储空间占用_02

第三次

Java中有100万个对象,用list map泛型存储和用list对象泛型存储,那个占用空间大,为什么_集合_03