使用到的工具是lucene
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>4.2.0</version>
</dependency>
注意版本,新版本好像不能计算一些自定义对象和集合,只能计算基本类型的数组
当一个对象没有任何属性和占用空间时,这个对象结构框架实际上也是有占用一定的空间的,那就是对象头。
Java对象内存布局
对象头(Header),实例数据(Instance Data)和对齐填充(Padding)
另外,不同环境Java对象占用内存空间可能有所差异。本文实验环境如下,HotSpot 64-Bit虚拟机,默认开启指针压缩(-XX:+UseCompressedOops),结合如图1,所以Java对象实例的对象头大小为12bytes(8bytes makOop + 4 bytes klassOop), Java数组实例的对象头大小为16bytes(8bytes makOop + 4 bytes klassOop + 4 bytes length);64位Linux系统,所以字节对齐必须是8的倍数。
可以通过java -verson查看自己当前JAVA虚拟机的版本
原生类型:
对于8种基本类型,他们实际上会自动封装成一个包装类型
则以一个int 类型的变量为例子:
int i = 1;
RamUsageEstimator.sizeOf(i)
结果为 :16
其结构为:12(Header) + 4(Instance Data)=16 bytes
12(Header) + 4(Instance Data)=16 bytes
对象头大小 int类型的值大小
如果是char类型
char c = ‘c’;
RamUsageEstimator.sizeOf©
结果为:16
但是他的结构有所不同:
12(Header) + 2(Instance Data) + 2(Padding)=16 bytes
对象头 值占用 填充
因为 12 + 2 =14不是8的倍数,所以填充占的两位是为了让结构统一的
基本类型与他们对应的实际包装类型其实是一致的。
对于null,和Object这两个特殊对象
null占0字节
Object占 16字节
数组
对于int类型数组
int[] array0 = new int[0];
int[] array1 = new int[1];
int[] array2 = new int[2];
占用情况为:
16(Header)=16 bytes
16(Header) + 4(int) + 4(Padding)=24 bytes
16(Header) + 4(int)*2=24 bytes
结构为: 对象头16 + 一个长度占用4byte长度
String
先看看源码:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;
private static final ObjectStreamField[] serialPersistentFields =
new ObjectStreamField[0];
}
这里其实只需要看非静态变量,静态变量不再对象的堆内存中,不纳入计算范围
一个用于存放字符串数据的char[], 一个int类型的hashcode
所以一个String对象占用的内存空间大小为:
40 + length * 2 bytes + Padding
如:
String s0 = “”;
String s1 = “a”;
String s2 = “aa”;
大小为:
40 + 0 * 2 = 40 bytes
40 + 1 * 2 + 6(Padding) = 48 bytes
40 + 2 * 2 + 4(Padding) = 48 bytes
ArrayList
看看部分源码:
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
private static final long serialVersionUID = 8683452581122892189L;
/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* Shared empty array instance used for empty instances.
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
transient Object[] elementData; // non-private to simplify nested class access
/**
* The size of the ArrayList (the number of elements it contains).
*/
private int size;
}
对于非静态变量只有一个用于存放数组元素的Object[], 一个int类型的size。
因此,一个ArrayList本身需要 12(Header) + 4(Object[] reference) + 4(int) + 4(Padding) = 24 bytes。
除此之外,一个Object[]占用16(Array Header) + length * 4(Object reference) bytes(8字节对齐),length是Object[]长度,即ArrayList容量,size是ArrayList存放的元素数量,其中length >= size,另加数组初始化的Object占用的内存空间,如下图,所以一个ArrayList占用的内存空间大小为:
((40 + length * 4)(8字节对齐) + size * n bytes)(8字节对齐),假设Object对象占用n bytes,size * n表示只有在数组初始化的Object才需要分配内存空间。