在 Java 中,使用 List<Map<泛型类型, 泛型类型>>
存储 100 万个对象和使用 List<对象类型>
存储 100 万个对象,通常情况下 List<Map<泛型类型, 泛型类型>>
占用的空间更大。下面详细分析原因:
内存占用情况分析
1. List<对象类型>
存储方式
当使用 List<对象类型>
存储对象时,List
本身会维护一个内部数组来存储这些对象的引用。每个对象会在堆内存中占据一定的空间,而 List
只需要存储这些对象的引用。
登录后复制
java
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));
}
}
}
在这个例子中,List
只需要存储 100 万个 MyObject
对象的引用,而每个 MyObject
对象包含一个 int
类型的 id
和一个 String
类型的 name
。
2. List<Map<泛型类型, 泛型类型>>
存储方式
当使用 List<Map<泛型类型, 泛型类型>>
存储对象时,List
同样会维护一个内部数组来存储 Map
对象的引用。而每个 Map
对象本身也需要占用一定的内存空间,并且 Map
内部会存储键值对,每个键值对也会占用额外的内存。
登录后复制
java
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);
}
}
}
在这个例子中,List
需要存储 100 万个 Map
对象的引用,每个 Map
对象内部又存储了键值对,除了存储与 MyObject
相同的数据外,Map
本身还有额外的开销,例如哈希表的数组、链表节点等。
占用空间大的原因总结
- 额外的数据结构开销 :
Map
是一种复杂的数据结构,为了实现高效的查找、插入和删除操作,Map
内部使用了哈希表等数据结构,这些数据结构需要额外的内存空间来存储。例如,HashMap
内部会维护一个数组和链表(或红黑树)来解决哈希冲突,这些都会增加内存占用。 - 键值对的包装开销 :在
Map
中,每个键值对都需要封装成一个Entry
对象,这也会增加额外的内存开销。
测试类
登录后复制
java
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("两种存储方式占用的内存相同。");
}
}
}
运行结果
100万个对象运行3次的结果
第一次
![](https://i-blog.csdnimg.cn/img_convert/f1310098b44222655e0cd07f899917ce.png)
第二次
![](https://i-blog.csdnimg.cn/img_convert/d86f1c4933f012fded720f59e3795aa5.png)
第三次
![](https://i-blog.csdnimg.cn/img_convert/7fd59240934b04f0303449e1ffa2c8f1.png)