Home  >  Article  >  Java  >  How much memory does a java object occupy?

How much memory does a java object occupy?

伊谢尔伦
伊谢尔伦Original
2016-11-26 11:45:441578browse

Recently, I was reading "In-depth Understanding of Java Virtual Machine" and gained a better understanding of the memory layout of Java objects. So a very common question naturally came to my mind, which is how much memory does a Java object occupy?

I found a very good blog on the Internet: http://yueyemaitian.iteye.com/blog/2033046. The class provided in it is also very practical:

import java.lang.instrument.Instrumentation; 
import java.lang.reflect.Array; 
import java.lang.reflect.Field; 
import java.lang.reflect.Modifier; 
import java.util.ArrayDeque; 
import java.util.Deque; 
import java.util.HashSet; 
import java.util.Set; 
   
/**
 * 对象占用字节大小工具类
 *
 * @author tianmai.fh
 * @date 2014-03-18 11:29
 */ 
public class SizeOfObject { 
    static Instrumentation inst; 
   
    public static void premain(String args, Instrumentation instP) { 
        inst = instP; 
    } 
   
    /**
     * 直接计算当前对象占用空间大小,包括当前类及超类的基本类型实例字段大小、<br></br>
     * 引用类型实例字段引用大小、实例基本类型数组总占用空间、实例引用类型数组引用本身占用空间大小;<br></br>
     * 但是不包括超类继承下来的和当前类声明的实例引用字段的对象本身的大小、实例引用数组引用的对象本身的大小 <br></br>
     *
     * @param obj
     * @return
     */ 
    public static long sizeOf(Object obj) { 
        return inst.getObjectSize(obj); 
    } 
   
    /**
     * 递归计算当前对象占用空间总大小,包括当前类和超类的实例字段大小以及实例字段引用对象大小
     *
     * @param objP
     * @return
     * @throws IllegalAccessException
     */ 
    public static long fullSizeOf(Object objP) throws IllegalAccessException { 
        Set<Object> visited = new HashSet<Object>(); 
        Deque<Object> toBeQueue = new ArrayDeque<Object>(); 
        toBeQueue.add(objP); 
        long size = 0L; 
        while (toBeQueue.size() > 0) { 
            Object obj = toBeQueue.poll(); 
            //sizeOf的时候已经计基本类型和引用的长度,包括数组 
            size += skipObject(visited, obj) ? 0L : sizeOf(obj); 
            Class<?> tmpObjClass = obj.getClass(); 
            if (tmpObjClass.isArray()) { 
                //[I , [F 基本类型名字长度是2 
                if (tmpObjClass.getName().length() > 2) { 
                    for (int i = 0, len = Array.getLength(obj); i < len; i++) { 
                        Object tmp = Array.get(obj, i); 
                        if (tmp != null) { 
                            //非基本类型需要深度遍历其对象 
                            toBeQueue.add(Array.get(obj, i)); 
                        } 
                    } 
                } 
            } else { 
                while (tmpObjClass != null) { 
                    Field[] fields = tmpObjClass.getDeclaredFields(); 
                    for (Field field : fields) { 
                        if (Modifier.isStatic(field.getModifiers())   //静态不计 
                                || field.getType().isPrimitive()) {    //基本类型不重复计 
                            continue; 
                        } 
   
                        field.setAccessible(true); 
                        Object fieldValue = field.get(obj); 
                        if (fieldValue == null) { 
                            continue; 
                        } 
                        toBeQueue.add(fieldValue); 
                    } 
                    tmpObjClass = tmpObjClass.getSuperclass(); 
                } 
            } 
        } 
        return size; 
    } 
   
    /**
     * String.intern的对象不计;计算过的不计,也避免死循环
     *
     * @param visited
     * @param obj
     * @return
     */ 
    static boolean skipObject(Set<Object> visited, Object obj) { 
        if (obj instanceof String && obj == ((String) obj).intern()) { 
            return true; 
        } 
        return visited.contains(obj); 
    } 
}

You can use this code to read and verify , please note that running this program requires injecting Instrumentation through javaagent. For details, please see the original blog. Today I mainly summarize the basic rules for manually calculating the number of bytes occupied by Java objects. As a basic skill, get√ is required. I hope it can help Java novices like me.

Before the introduction, let’s briefly review the memory layout of Java objects: object header (Header), instance data (Instance Data) and alignment padding (Padding). For details, you can see my reading notes. In addition: the results may be different in different environments. My environment is a HotSpot virtual machine and 64-bit Windwos.

 Now enter the text:

 Object header

 The object header occupies 8 bytes on 32-bit systems and 16 bytes on 64-bit systems.

How much memory does a java object occupy?

Instance data

 The memory usage of primitive type is as follows:

Primitive Type Memory Required(bytes)

boolean 1

byte 1

short 2

char 2

int 4

float 4

long 8

double 8

 The reference type occupies 4 bytes each on 32-bit systems, and 8 bytes each on 64-bit systems.

 Alignment padding

  HotSpot’s alignment is 8-byte alignment:

(object header + instance data + padding) % 8 equals 0 and 0

 Pointer compression

 Memory occupied by the object The size is affected by the VM parameter UseCompressedOops.

 1) Impact on object header

 Turn on (-XX:+UseCompressedOops) and the object header size is 12 bytes (64-bit machine).

static class A {
        int a;
    }

Memory occupied by object A:

Turn off pointer compression: 16+4=20 is not a multiple of 8, so +padding/4=24

How much memory does a java object occupy?

Turn on pointer compression: 12+4=16 It is already a multiple of 8, no padding is needed.

How much memory does a java object occupy?

  2) Impact on the reference type

  The reference type occupies 8 bytes on a 64-bit machine, and occupies 4 bytes after turning on pointer compression.

static class B2 {
        int b2a;
        Integer b2b;
}

B2 object memory usage:

Turn off pointer compression: 16+4+8=28 is not a multiple of 8, so +padding/4=32

How much memory does a java object occupy?

Turn on pointer compression: 12+4+4 =20 is not a multiple of 8, so +padding/4=24

How much memory does a java object occupy?

Array object

On a 64-bit machine, the object header of the array object occupies 24 bytes, and occupies 16 bytes after enabling compression. The reason why it takes up more memory than ordinary objects is that extra space is needed to store the length of the array.

First consider the memory size occupied by new Integer[0]. The length is 0, which is the size of the object header:

Without compression: 24 bytes

How much memory does a java object occupy?

With compression turned on: 16 bytes

How much memory does a java object occupy?

  Then it’s easy to calculate new Integer[1], new Integer[2], new Integer[3] and new Integer[4]:

Compression is not turned on:

How much memory does a java object occupy?

  开启压缩:

How much memory does a java object occupy?

  拿new Integer[3]来具体解释下:

  未开启压缩:24(对象头)+8*3=48,不需要padding;

  开启压缩:16(对象头)+3*4=28,+padding/4=32,其他依次类推。

  自定义类的数组也是一样的,比如:

static class B3 {
        int a;
        Integer b;
    }

    new B3[3]占用的内存大小:

  未开启压缩:48

  开启压缩后:32

  复合对象

  计算复合对象占用内存的大小其实就是运用上面几条规则,只是麻烦点。

  1)对象本身的大小

  直接计算当前对象占用空间大小,包括当前类及超类的基本类型实例字段大小、引用类型实例字段引用大小、实例基本类型数组总占用空间、实例引用类型数组引用本身占用空间大小; 但是不包括超类继承下来的和当前类声明的实例引用字段的对象本身的大小、实例引用数组引用的对象本身的大小。

static class B {
        int a;
        int b;
    }
static class C {
        int ba;
        B[] as = new B[3];
 
        C() {
            for (int i = 0; i < as.length; i++) {
                as[i] = new B();
            }
        }
    }

    未开启压缩:16(对象头)+4(ba)+8(as引用的大小)+padding/4=32

  开启压缩:12+4+4+padding/4=24

  2)当前对象占用的空间总大小

  递归计算当前对象占用空间总大小,包括当前类和超类的实例字段大小以及实例字段引用对象大小。

  递归计算复合对象占用的内存的时候需要注意的是:对齐填充是以每个对象为单位进行的,看下面这个图就很容易明白。

How much memory does a java object occupy?

现在我们来手动计算下C对象占用的全部内存是多少,主要是三部分构成:C对象本身的大小+数组对象的大小+B对象的大小。

  未开启压缩:

  (16 + 4 + 8+4(padding)) + (24+ 8*3) +(16+8)*3 = 152bytes

  开启压缩:

  (12 + 4 + 4 +4(padding)) + (16 + 4*3 +4(数组对象padding)) + (12+8+4(B对象padding))*3= 128bytes

  大家有兴趣的可以试试。

  实际工作中真正需要手动计算对象大小的场景应该很少,但是个人觉得做为基础知识每个Java开发人员都应该了解,另外:对自己写的代码大概占用多少内存,内存中是怎么布局的应该有一个直觉性的认识。


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn