jvm内存占用模型

对象的内存结构

对象头 Header

包含两部分数据Mark Word和Kclass:

Mark Word:存储对象自身的运行时数据,如hashCode、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。这部分数据的长度在32位和64的虚拟机(未开启指针压缩)中分别为4B和8B,官方称之为”Mark Word”。

类型指针 Kclass:即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是那个类的实例。

如果对象是一个Java数组,那再对象头中还必须有一块用于记录数组长度的数据。

对象头在32位系统上占用8B,64位系统上占16B。 无论是32位系统还是64位系统,对象都采用8字节对齐。Java在64位模式下开启指针压缩,比32位模式下,头部会大4B(mark区域变位8B,kclass区域被压缩为4B),如果没有开启指针压缩,头部会大8B(mark和kclass都是8B)

实例数据 Instance Data

存放字段数据。

对齐填充 Padding

对象的起始地址必须是8字节的整数倍(对象大小=8字节*整数),如果没有对齐时,需要通过对齐填充来补全。

综上,对象内存占用情况如下:

对象总内存 = 对象头(Header(Mark Word+Kclass))+实例数据(Instance Data)+对齐填充(Padding)
32位虚拟机:header (8B)=Mark Word(4B)+kclass(4B)
64位没有开启指针压缩:header (16B)=Mark Word(8B)+kclass(8B)
64位开启指针压缩:header (12B)=Mark Word(8B)+kclass(4B)

详细了解jvm理论

jvm理论

jvm工具

基于maven的内存分析工具

项目结构

SizeOfAgent

package com.mobjia.agent;

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 SizeOfAgent {
    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);
    }
}

AgentMain

package com.mobjia.agent;

import java.io.File;
import java.util.HashMap;

public class AgentMain {
    /**
     * -XX:+UseCompressedOops: mark/4 + metedata/8 + 4 = 16
     * -XX:-UseCompressedOops: mark/8 + metedata/8 + 4 + padding/4 = 24
     */
    static class A {
        int a;
    }  

    /**
     * -XX:+UseCompressedOops: mark/4 + metedata/8 + 4 + 4 + padding/4 = 24
     * -XX:-UseCompressedOops: mark/8 + metedata/8 + 4 + 4 = 24
     */
    static class B {
        int a;
        int b;
    }  

    /**
     * -XX:+UseCompressedOops: mark/4 + metedata/8 + 4 + 4 + padding/4 = 24
     * -XX:-UseCompressedOops: mark/8 + metedata/8 + 8 + 4 + padding/4 = 32
     */
    static class B2 {
        int b2a;
        Integer b2b;
    }  

    /**
     * 不考虑对象头:
     * 4 + 4 + 4 * 3 + 3 * sizeOf(B)
     */
    static class C extends A {
        int ba;
        B[] as = new B[3];  

        C() {
            for (int i = 0; i < as.length; i++) {
                as[i] = new B();
            }
        }
    }  

    static class D extends B {
        int da;
        Integer[] di = new Integer[3];
    }  

    /**
     * 会算上A的实例字段
     */
    static class E extends A {
        int ea;
        int eb;
    }  

    public static void main(String[] args) throws IllegalAccessException {
        primitiveType();
        wrapperType();
    }  

    private static void  primitiveType(){

      //逻辑型boolean
      boolean boolean1 =true;
      System.out.println("sizeOf(boolean)=" + SizeOfAgent.sizeOf(boolean1));

      //文本型char
      char char1 = 0;
      System.out.println("sizeOf(char)=" + SizeOfAgent.sizeOf(char1));

      //整数型(byte、short、int、long)
      byte byte1 = 0;
      System.out.println("sizeOf(byte)=" + SizeOfAgent.sizeOf(byte1));

      short short1 = 0;
      System.out.println("sizeOf(short)=" + SizeOfAgent.sizeOf(short1));

      int int1 = 0;
      System.out.println("sizeOf(int)=" + SizeOfAgent.sizeOf(int1));

      long long1 = 0;
      System.out.println("sizeOf(long)=" + SizeOfAgent.sizeOf(long1));

      //浮点型(float、double)
      float float1 = 0;
      System.out.println("sizeOf(float)=" + SizeOfAgent.sizeOf(float1));

      double double1 =1;
      System.out.println("sizeOf(double)=" + SizeOfAgent.sizeOf(double1));

    } 

    private static void  wrapperType(){

        //逻辑型boolean
          java.lang.Boolean boolean1 =true;
        System.out.println("sizeOf(java.lang.boolean)=" + SizeOfAgent.sizeOf(boolean1));

        //文本型char
        java.lang.Character char1 = 0;
        System.out.println("sizeOf(java.lang.Character)=" + SizeOfAgent.sizeOf(char1));

        //整数型(byte、short、int、long)
        java.lang.Byte byte1 = 0;
        System.out.println("sizeOf(java.lang.Byte)=" + SizeOfAgent.sizeOf(byte1));

        java.lang.Short short1 = 0;
        System.out.println("sizeOf(java.lang.Short)=" + SizeOfAgent.sizeOf(short1));

        java.lang.Short int1 = 0;
        System.out.println("sizeOf(java.lang.Short)=" + SizeOfAgent.sizeOf(int1));

        java.lang.Long long1 = 0l;
        System.out.println("sizeOf(java.lang.Long)=" + SizeOfAgent.sizeOf(long1));

        //浮点型(float、double)
        java.lang.Float float1 = 0f;
        System.out.println("sizeOf(java.lang.Float)=" + SizeOfAgent.sizeOf(float1));

        java.lang.Double double1 =1d;
        System.out.println("sizeOf(java.lang.Double)=" + SizeOfAgent.sizeOf(double1));

      } 

}

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.mobjia</groupId>
  <artifactId>mobjia-jvm</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>mobjia-jvm</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
        <plugins>
            <plugin>
               <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>2.4</version>
                <configuration>
                    <finalName>SizeOfAgent</finalName>
                    <archive>
                        <manifestEntries>
                            <Premain-class>com.mobjia.agent.SizeOfAgent</Premain-class>
                            <Boot-Class-Path></Boot-Class-Path>
                            <Can-Redefine-Classes>false</Can-Redefine-Classes>
                        </manifestEntries>
                        <addMavenDescriptor>false</addMavenDescriptor>
                    </archive>
                </configuration>
            </plugin>
         <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>1.2.1</version>
        <executions>
            <execution>
                <phase>package</phase>
                <goals>
                        <goal>shade</goal>
                </goals>
                    <configuration>
                        <transformers>
                            <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                <mainClass>com.mobjia.agent.AgentMain</mainClass>
                            </transformer>
                        </transformers>
                    </configuration>
            </execution>
        </executions>
     </plugin>
        </plugins>
         <defaultGoal>compile</defaultGoal>
    </build>
</project>

java基本类型内存占用分析

以下是基于64位HotSpot虚拟机。

生成jar包

通过maven install 直接生成jar包,jar包在 项目\target文件夹下。

基本类型内存占用情况

开启指针压缩

通过vm参数 -XX:+UseCompressedOops 开启指针压缩

boolean

对象头

header(12B)=Mark Word(8B)+kclass(4b)

实例数据

Instance Data (1B)

对齐填充

Padding = 2*8B -( header(12B)+(1B)) = 3B

所以boolean占用16B

int

对象头

header(12B)=Mark Word(8B)+kclass(4b)

实例数据

Instance Data (4B)

对齐填充

Padding = 2*8B -( header(12B)+(4B)) = 0B

所以int占用16B

long

对象头

header(12B)=Mark Word(8B)+kclass(4b)

实例数据

Instance Data (8B)

对齐填充

Padding = 3*8B -( header(12B)+(8B)) = 4B

所以long占用24B

关闭指针压缩

通过vm参数 -XX:-UseCompressedOops 关闭指针压缩

boolean

对象头

header(16B)=Mark Word(8B)+kclass(8b)

实例数据

Instance Data (1B)

对齐填充

Padding = 3*8B -( header(16B)+(1B)) = 7B

所以boolean占用24B

int

对象头

header(16B)=Mark Word(8B)+kclass(8b)

实例数据

Instance Data (4B)

对齐填充

Padding = 3*8B -( header(16B)+(4B)) = 4B

所以int占用24B

long

对象头

header(16B)=Mark Word(8B)+kclass(8b)

实例数据

Instance Data (8B)

对齐填充

Padding = 3*8B -( header(16B)+(8B)) = 0B

所以long占用24B

jvm实战-基本类型占多少内存的更多相关文章

  1. java对象占多少内存

    通常来说Hotspot jvm的对内存中的对象由以下几个部分组成 一个对象头,包含了一些整理工作所需信息 原始类型字段,不同类型大小各异(表1) 引用字段,占据4个字节(byte) 填充,在对象的末尾 ...

  2. 【JVM.2】垃圾收集器与内存分配策略

    垃圾收集器需要完成的3件事情: 哪些内存需要回收? 什么时候回收? 如何回收? 在前一节中介绍了java内存运行时区域的各个部分,其中程序计数器.虚拟机栈.本地方法栈3个区域随线程而生,随线程而灭:栈 ...

  3. 【转】深入JVM系列(一)之内存模型与内存分配

    http://lovnet.iteye.com/blog/1825324 一.JVM内存区域划分   大多数 JVM 将内存区域划分为 Method Area(Non-Heap),Heap,Progr ...

  4. JVM性能优化系列-(1) Java内存区域

    1. Java内存区域 1.1 运行时数据区 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.主要包括:程序计数器.虚拟机栈.本地方法栈.Java堆.方法区(运 ...

  5. JVM实战调优(空格引发的服务异常)

    JVM实战调优 问题描述 某一个项目中有一个文字转语音的服务,使用的是科大讯飞的语音转换服务,需要调用三方服务.因其转换服务是一个耗时操作,官方给的demo使用的是 WebSocket 进行数据转换操 ...

  6. JVM | 第1部分:自动内存管理与性能调优《深入理解 Java 虚拟机》

    目录 前言 1. 自动内存管理 1.1 JVM运行时数据区 1.2 Java 内存结构 1.3 HotSpot 虚拟机创建对象 1.4 HotSpot 虚拟机的对象内存布局 1.5 访问对象 2. 垃 ...

  7. JVM实用参数(四)内存调优

    理想的情况下,一个Java程序使用JVM的默认设置也可以运行得很好,所以一般来说,没有必要设置任何JVM参数.然而,由于一些性能问题(很不幸的是,这些问题经常出现),一些相关的JVM参数知识会是我们工 ...

  8. JVM学习笔记(四)------内存调优【转】

    转自:http://blog.csdn.net/cutesource/article/details/5907418 版权声明:本文为博主原创文章,未经博主允许不得转载. 首先需要注意的是在对JVM内 ...

  9. JVM学习笔记(四)------内存调优

    首先需要注意的是在对JVM内存调优的时候不能只看操作系统级别Java进程所占用的内存,这个数值不能准确的反应堆内存的真实占用情况,因为GC过后这个值是不会变化的,因此内存调优的时候要更多地使用JDK提 ...

随机推荐

  1. [译]Java 设计模式之备忘录

    (文章翻译来自Java Design Pattern: Memento) memento是一个保存另外一个对象内部状态拷贝的对象.这样以后就可以将该对象恢复到原先保存的状态. 在将来时空旅行将成为显示 ...

  2. WEB项目(B/S系统)打包安装(总结篇)

    原文:WEB项目(B/S系统)打包安装(总结篇) 打包安装程序的制作选择性还很多的,有installshield,wise installer,inno setup这几个做打包安装项目都是很强大的,要 ...

  3. qsort 排序功能 总结

    qsort包括在<stdlib.h>头文件里.此函数依据你给的比較条件进行高速排序,通过指针移动实现排序. 排序之后的结果仍然放在原数组中.使用qsort函数必须自己写一个比較函数. 函数 ...

  4. Ruby on Rails (ROR)类书籍

    Ruby on Rails (ROR)类书籍下载地址及其他(整理) Ruby on Rails 如此之热,忍不住也去看了看热闹,现在把一些相关的电子图书下载地址整理下,方便有兴趣的朋友. 2006-0 ...

  5. [转]How To Use CSS3 Media Queries To Create a Mobile Version of Your Website

    CSS3 continues to both excite and frustrate web designers and developers. We are excited about the p ...

  6. Java 8新特性前瞻

    快端午小长假了,要上线的项目差不多完结了,终于有时间可以坐下来写篇博客了. 这是篇对我看到的java 8新特性的一些总结,也是自己学习过程的总结. 几乎可以说java 8是目前为止,自2004年jav ...

  7. 在现有代码中通过async/await实现并行

    在现有代码中通过async/await实现并行 一项新技术或者一个新特性,只有你用它解决实际问题后,才能真正体会到它的魅力,真正理解它.也期待大家能够多分享解一些解决实际问题的内容. 在我们遭遇“黑色 ...

  8. Memcached快递上手之C#

    Memcached快递上手之C# Memcached是开源高性能分布式缓存组件,目前已经广泛应用各类互联网领域. 具有多种语言的客户端开发包,包括:Perl/PHP/JAVA/C/Python/Rub ...

  9. 网际协议:无连接数据报交付(IPv4)

    一.数据报格式:

  10. jquery 实现飘落效果

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...