jvm实战-基本类型占多少内存
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理论
基于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实战-基本类型占多少内存的更多相关文章
- java对象占多少内存
通常来说Hotspot jvm的对内存中的对象由以下几个部分组成 一个对象头,包含了一些整理工作所需信息 原始类型字段,不同类型大小各异(表1) 引用字段,占据4个字节(byte) 填充,在对象的末尾 ...
- 【JVM.2】垃圾收集器与内存分配策略
垃圾收集器需要完成的3件事情: 哪些内存需要回收? 什么时候回收? 如何回收? 在前一节中介绍了java内存运行时区域的各个部分,其中程序计数器.虚拟机栈.本地方法栈3个区域随线程而生,随线程而灭:栈 ...
- 【转】深入JVM系列(一)之内存模型与内存分配
http://lovnet.iteye.com/blog/1825324 一.JVM内存区域划分 大多数 JVM 将内存区域划分为 Method Area(Non-Heap),Heap,Progr ...
- JVM性能优化系列-(1) Java内存区域
1. Java内存区域 1.1 运行时数据区 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.主要包括:程序计数器.虚拟机栈.本地方法栈.Java堆.方法区(运 ...
- JVM实战调优(空格引发的服务异常)
JVM实战调优 问题描述 某一个项目中有一个文字转语音的服务,使用的是科大讯飞的语音转换服务,需要调用三方服务.因其转换服务是一个耗时操作,官方给的demo使用的是 WebSocket 进行数据转换操 ...
- JVM | 第1部分:自动内存管理与性能调优《深入理解 Java 虚拟机》
目录 前言 1. 自动内存管理 1.1 JVM运行时数据区 1.2 Java 内存结构 1.3 HotSpot 虚拟机创建对象 1.4 HotSpot 虚拟机的对象内存布局 1.5 访问对象 2. 垃 ...
- JVM实用参数(四)内存调优
理想的情况下,一个Java程序使用JVM的默认设置也可以运行得很好,所以一般来说,没有必要设置任何JVM参数.然而,由于一些性能问题(很不幸的是,这些问题经常出现),一些相关的JVM参数知识会是我们工 ...
- JVM学习笔记(四)------内存调优【转】
转自:http://blog.csdn.net/cutesource/article/details/5907418 版权声明:本文为博主原创文章,未经博主允许不得转载. 首先需要注意的是在对JVM内 ...
- JVM学习笔记(四)------内存调优
首先需要注意的是在对JVM内存调优的时候不能只看操作系统级别Java进程所占用的内存,这个数值不能准确的反应堆内存的真实占用情况,因为GC过后这个值是不会变化的,因此内存调优的时候要更多地使用JDK提 ...
随机推荐
- 编程算法 - 二部图确定 代码(C)
二部图确定 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 给定一个具有n个顶点的图. 要给图上每一个顶点染色, 而且要使相邻的顶点颜色不同. ...
- C#中使用消息队列RabbitMQ
在C#中使用消息队列RabbitMQ 2014-10-27 14:41 by qy1141, 745 阅读, 2 评论, 收藏, 编辑 1.什么是RabbitMQ.详见 http://www.rabb ...
- sql 事务日志传输
原文:sql 事务日志传输 概述 可以使用日志传送将事务日志不间断地从一个数据库(主数据库)发送到另一个数据库(辅助数据库).不间断地备份主数据库中的事务日志,然后将它们复制并还原到辅助数据库,这将使 ...
- SQL Server中如何备份存储过程(SP)和函数(Fun)
考虑到安全因素,我们经常需要对数据库的存储过程(SP)和函数(Fun)进行备份 下面提供了一种简单的方式, 存储过程(SP)SQL代码如下: select p.name as SpName,m.def ...
- RabbitMq install on Centos6.3
安装服务(root) step 1: 启用EPEL:EPEL是一个Fedora Project 推出的 EPEL(Extra Packages for Enterprise Linux),EPEL是 ...
- Android调用本机应用市场,实现应用评分功能
原本以为应用评分是个很小的功能,但是一实现才发现真不是个小事.网上搜索资料没有找到答案,在很多开发群里面询问了很多人也没有解决问题,最后分析log,反编译看源码才终于有了些眉目,好吧,上代码: try ...
- java class load
https://mp.weixin.qq.com/s?__biz=MjM5NzMyMjAwMA==&mid=403638649&idx=2&sn=4f17e8b58c64875 ...
- C# 学习笔记1 .NET平台,C#的重要概念
.NET平台构成的三个关键实体是: 1.CLR(公共语言运行库):为我们定位,加载,管理.NET类型,同时负责一些底层细节的工作,如内存管理,应用托管,处理线程,安全检查等,它包含了一个重要名为msc ...
- C#中另辟蹊径解决JSON / XML互转的问题
C#中另辟蹊径解决JSON / XML互转的问题 最近在一个POC的项目中要用到JSON和XML的相互转换, 虽然我知道很多类库如JSON.NET具备这种功能, 但是我还是另辟蹊径的使用Spider ...
- discuz的门户文章页中增加百度分享代码
discuz虽然有百度分享插件,但是不太想用,于是自己手动添加了百度分享代码: 一.在http://share.baidu.com/地址中申请设置自己的百度分享代码,选择的风格完全按照个人喜好进行选择 ...