在 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次的结果
第一次
第二次
第三次