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提 ...
随机推荐
- SQL点滴23—T-SQL中的除法
原文:SQL点滴23-T-SQL中的除法 在T-SQL中没有除法运算,但是在T-SQL中可以实现类似除法的操作Divide.一般除法操作的结果一个列来自于被除关系表,剩下的来自除关系表.这里举一个例子 ...
- Eclipse 使用技巧合辑
修改Eclipse默认JDK "window"(窗口)---"Preferences.."(首选项),然后在弹出的对话框中的左边:选"Java&quo ...
- SSRS (SQL Server Report Service) 在IE9, IE10下显示不全的解决办法
原文:SSRS (SQL Server Report Service) 在IE9, IE10下显示不全的解决办法 在做项目的过程中遇到SSRS与IE9, IE10不兼容的情况,具体表现为报表页面在IE ...
- [译]Java 设计模式 之模板方法
(文章翻译自Java Design Pattern: Template Method) 模板方法设计模式定义了归档特定操作的工作流.它允许子类去修改特定的步奏而不用改变工作流的结构. 下面的例子表示模 ...
- 实时预览的在线 Markdown 编辑器 - Markdoc
实时预览的在线 Markdown 编辑器 - Markdoc 最近组内需要为一些项目和系统写文档,发表在公司内的文档平台上,这个平台并不支持markdown,所以打算做一个在线markdown编辑器, ...
- ASP.NET MVC IOC之Unity攻略
ASP.NET MVC IOC之Unity攻略 一.你知道IOC与DI吗? 1.IOC(Inversion of Control )——控制反转 即依赖对象不在被依赖模块的类中直接通过new来获取 先 ...
- 来自 Repository 的一丝线索,Domain Model 再重新设计
来自 Repository 的一丝线索,Domain Model 再重新设计 写在前面 阅读目录: 疑惑解读 设计窘境 一幅图的灵感 为嘛还是你-Repository 后记 上一篇<No zuo ...
- myeclipse搭建svn插件
在网上查了一下,安装的方法有几种,这里给大家推荐一种快速安装的方法. //第一步 : 下载 site-1.6.5.zip //===================================== ...
- 序列化(ObjectOutputStream和ObjectInputStream)(切记:out是输出到本地中,in是输入到程序中)
注意:序列化自定义类必须实现一个接口Serializable,在c#中序列化自定义类是使用特性也就是[Serializable] //要实现序列化的类 public class Student imp ...
- asp.net MVC中的AppendTrailingSlash以及LowercaseUrls
asp.net MVC中的AppendTrailingSlash以及LowercaseUrls asp.net MVC是一个具有极大扩展性的框架,可以在从Url请求开始直到最终的html的渲染之间进行 ...