Map<Object, Object> map = new HashMap<>();
日常写代码中,可能都不会关注这一行代码占了多少个内存,今天我们就来分析一下。
首先,map是一个对象,而java对象包含了三个部分:
- 对象头
- 实例数据
- 对齐填充字节
对象内存分析
java对象头
我们先来看看对象头,对象头中也分为了三部分:
- Mark Word
- class pointer
- array length(只有数组对象才有)
我们目前只考虑在64位下并默认开启压缩的情况下的内存,map对象不属于数组对象,即只包括了8bytes的Mark Word和4bytes的class pointer,所以对象头总共包含了12bytes。
实例数据
实例数据包括自身的实例数据以及所有父类对象的实例字段:
首先我们看一下HashMap继承的父类AbstractMap源码中,里面的实例字段:
transient Set<K> keySet;
transient Collection<V> values;
看一下HashMap源码的实例字段:
/* ---------------- Fields -------------- */
/**
* The table, initialized on first use, and resized as
* necessary. When allocated, length is always a power of two.
* (We also tolerate length zero in some operations to allow
* bootstrapping mechanics that are currently not needed.)
*/
transient Node<K,V>[] table;
/**
* Holds cached entrySet(). Note that AbstractMap fields are used
* for keySet() and values().
*/
transient Set<Map.Entry<K,V>> entrySet;
/**
* The number of key-value mappings contained in this map.
*/
transient int size;
/**
* The number of times this HashMap has been structurally modified
* Structural modifications are those that change the number of mappings in
* the HashMap or otherwise modify its internal structure (e.g.,
* rehash). This field is used to make iterators on Collection-views of
* the HashMap fail-fast. (See ConcurrentModificationException).
*/
transient int modCount;
/**
* The next size value at which to resize (capacity * load factor).
*
* @serial
*/
// (The javadoc description is true upon serialization.
// Additionally, if the table array has not been allocated, this
// field holds the initial array capacity, or zero signifying
// DEFAULT_INITIAL_CAPACITY.)
int threshold;
/**
* The load factor for the hash table.
*
* @serial
*/
final float loadFactor;
由以上源码可以知道,有4个引用字段,3个int类型字段,1个float字段;引用类型占4个字节,int类型占4个字节,float类型占4个字节;可以算出,一个HashMap对象的实例数据占32个字节。
对齐填充
JVM要求对象内存大小必须是8bytes的倍数,综上所述对象头12bytes加上实例数据32bytes,总共44bytes,填充4bytes,所以最后得出结论,一个HashMap对象所占内存为48bytes。
结论
一个HashMap对象所占内存为48bytes。