java对象内存占用_Java对象在内存中占用的空间

本文主要结合lucene中RamUsageEstimator类来谈谈Java对象在内存中占用的空间大小。

注意这种计算方式适用于OpenJDK和Oracle JDK两个版本,其它版本可能有所不同。

从整体来看,java对象由对象头、实例数据、对齐填充3个部分组成,其中对齐填充是指对象头的占用空间与实例数据的占用空间如果不是8的整数倍,就需要添加pad填满直到总的占用空间为8的倍数。这里暂时说的8的整数倍,因为在lucene源码中64位的虚拟机是动态获取的(具体原因暂时不清楚,如果像网上和书上说的是固定8的整数倍就没必要动态获取了,尽信书不如无书有些东西没看到源码前最好别下定论),32位是固定的8个字节。对象引用的大小在64位jvm中如果开启指针压缩为4个字节否则8个字节,在32位jvm中只占4个字节。

普通对象的对象头大小为对象引用的大小加上8字节,数组的对象头等于普通对象头的大小加上4个字节的和并且要按照8字节对齐。

字节数组占用的空间=数组的对象头+1*数组个数的和并且按照8字节对齐;

boolean数组的占用空间与字节数组的占用空间相同;

char数组的占用空间=数组的对象头+2*数组个数的和并且按照8字节对齐;

short数组的占用空间与char数组的占用空间相同;

int数组的占用空间=数组的对象头+4*数组个数的和并且按照8字节对齐;

float数组的占用空间与int数组的占用空间相同;

long数组的占用空间=数组的对象头+8*数组个数的和并且按照8字节对齐;

double数组的占用空间与long数组的占用空间相同;

对象数组与以上数组稍有不同,数组中记录的是所有对象的引用地址,因此占用空间=数组的对象头+对象引用的大小*数组个数的和并且按照8字节对齐后再加上每个对象自身占用的实际空间;

现在详细说明每个对象的占用空间,除了对象头,其中的实例数据部分(不包括静态变量)包括基本类型和引用类型(所有的数组和普通对象都是引用类型)。引用类型的指针大小在上面已经说过,指向真正对象的占用空间就是现在讨论的,实际上这就是一个递归,例如:

class Test{

int a;

byte[] b=new byte[10];

}

假设在64位jvm中指针压缩的情况下,Test对象占用的空间=align(对象头(4+8)+数据(4+4))+size(b)。注意:所有的引用类型不与本对象在一个连续的地址空间中,所以字节对齐align时不能包含引用对象的实际大小!

在lucene中为了计算对象实际占用空间就需要实现Accountable接口,就是因为当对象内部存在一个对象引用时就需要计算引用对象实际占用空间!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java内存划分成两种:一种是栈内存,另一种是堆内存。在函数定义的一些基本类型的变量和对象的引用变量都是在函数的 栈内存分配,当在一段代码块定义一个变量时,Java 就在栈为这个变量分配内存空间,当超过变量的作用域后,Java 会自动 释放掉为该变量分配的内存空间,该内存空间可以立即被另作它用。 堆内存用来存放由 new 创建的对象数组,在堆分配的内存,由 Java 虚拟机的自动垃圾回收器来管理。在堆产生了一个数 组或者对象之后,还可以在栈定义一个特殊的变量,让栈的这个变量的取值等于数组对象在堆内存的首地址,栈的这个 变量就成了数组对象的引用变量,以后就可以在程序使用栈的引用变量来访问堆数组或者对象,引用变量就相当于是为 数组或者对象起的一个名称。引用变量是普通的变量,定义时在栈分配,引用变量在程序运行到其作用域之外后被释放。而数组对象本身在堆分配,即使程序运行到使用 new 产生数组或者对象的语句所在的代码块之外,数组对象本身占据的内存不会 被释放,数组对象在没有引用变量指向它的时候,才变为垃圾,不能在被使用,但仍然占据内存空间不放,在随后的一个不确定 的时间被垃圾回收器收走(释放掉)。这也是 Java 比较占内存的原因。 实际上,栈的变量指向堆内存的变量,这就是 Java 的指针!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值