如何java 获得对象类型java对象的内存地址

2012年3月 Java大版内专家分月排行榜第三
本帖子已过去太久远了,不再提供回复功能。java中对象、成员变量、静态变量、方法的内存分配 -
蛹 - ITeye技术网站
博客分类:
java中内存主要包含4块,即heap(堆内存)、stack(栈内存)、data segment(静态变量或是常量存放区)、codesegment(方法区).
堆内存中存放的是new出的对象,new出的对象只包含成员变量。
栈内存中:存放的是局部成员变量。对于基本的数据类型存放的是基本变量的值,而对于对象变量,存放的是堆内存的地址。
静态、常量区:存放的是静态变量(类变量)或是常量。
方法区:存放的是对象的方法。因此即使new出多个对象也是只是存在一个方法。

A a = new A(); A中含有一个work方法,2个成员变量a,b。那么对应的内存分配为
则 a是分配在栈内存中。里面存放了一个指向堆内存中存放的new A()的地址。
new A()会导致在堆内存中分配一块空间,该内存中的A对象同时会含有a和b。
work()方法会在codesegment区中分配内存。
如果此时 A b =则表示把a的值复制给b,即b的值为a中保存的地址
浏览 11663
JamesZhao1987
浏览: 135907 次
来自: 北京Java打印对象的内存地址 - 博客频道 - CSDN.NET
如果需要toString()方法打印出对象的内存地址,也许会这么写:
public class InfiniteRecursion {
public String toString() {
return "InfiniteRecursive address: " + this + "\n";
public static void main(String[] args) {
InfiniteRecursion ir = new InfiniteRecursion();
System.out.println(ir);
这样写代码运行时会出现异常。原因在于,在"InfiniteRecursive address: " + this + "\n";这里发生了自动类型转换,由this的InfiniteRecursion类型转换成String类型。编译器看到一个String类型的变量后面跟着一个“+”,而再后面的对象不是String类型,所以编译器会尝试着将this转换成一个String对象。问题来了,编译器要怎么转换呢?就是使用this的toString()方法,这样就会发生递归调用,产生了异常。
如果想要正确地打印出内存地址,应该调用Object.toString()方法,所以应该把toString()方法中的this改成super.toString()就没问题了。
排名:第14514名
(40)(37)(9)(3)(20)(0)(1)Java对象内存结构 - ImportNew
原文于日 发表, 日更新:还有一篇关于Java的Sizeof运算符的实用库的文章。
学C/C++出身的我,对Java有一点非常困惑,那就是缺乏计算对象占用内存大小的机制。而在C++中就可以通过sizeof运算符来获得基本类型以及类实例的大小。C和C++中的这个操作符对于指针运算、内存拷贝和IO操作都非常有用。
Java中并没有一个类似的运算符。事实上,Java也不需要这种运算符。Java中基本类型的大小在语言规范中已经定义了,而C/C++中基本类型大小则跟平台相关。Java有自己的通过序列化构建的IO框架。再者,由于Java中没有指针,因此指针运算和内存块拷贝之类的操作也不存在。
但是,Java程序员有时还是希望能知道一个Java对象到底用了多少内存的。不过这个问题的答案并不简单。
首先要区分清楚的是shallow size和deep size。Shallow size是指对象自身占用的内存大小,其引用对象的大小不算在内。而deep size,则是自身所占内存大小和其递归引用的所有对象所占内存大小的总和。大多数情况下,你会希望获得一个对象的deep size,但是为了知道这个值,首先要知道怎么算shallow size,下面我来介绍一下。
有人抱怨JVM规范中没有针对运行时Java对象的内存结构的说明,这也就是说JVM供应商可以按照自己的需要来实现这一点。后果就是,同一个类在不同的JVM上运行的实例对象占用的内存大小会有差别。好在是世界上大部分人(包括我在内)都使用Sun HotSpot虚拟机,这就大大简化了这个问题。我们接下来的讨论也会基于32位的Sun公司的JVM。下面我介绍一些规则来辅助解释JVM如何组织对象在内存中的布局的。
没有实例属性的类的内存布局
在Sun JVM中,(除了数组之外的)对象都有两个机器字(words)的头部。第一个字中包含这个对象的标示哈希码以及其他一些类似锁状态和等标识信息,第二个字中包含一个指向对象的类的引用。另外,任何对象都是8个字节为粒度进行对齐的。这就是对象内存布局的第一个规则:
规则1:任何对象都是8个字节为粒度进行对齐的。
比如,如果调用new Object(),由于Object类并没有其他没有其他可存储的成员,那么仅仅使用堆中的8个字节来保存两个字的头部即可。
继承了Object的类的内存布局
除了上面所说的8个字节的头部,类属性紧随其后。属性通常根据其大小来排列。例如,整型(int)以4个字节为单位对齐,长整型(long)以8个字节为单位对齐。这里是出于性能考虑而这么设计的:通常情况下,如果数据以4字节为单位对齐,那么从内存中读4字节的数据并写入到处理器的4字节寄存器是性价比更高的。
为了节省内存,Sun VM并没有按照属性声明时的顺序来进行内存布局。实际上,属性在内存中按照下面的顺序来组织:
1. 双精度型(doubles)和长整型(longs)
2. 整型(ints)和浮点型(floats)
3. 短整型(shorts)和字符型(chars)
4. 布尔型(booleans)和字节型(bytes)
5. 引用类型(references)
内存使用率会通过这个机制得到优化。例如,如下声明一个类:
class MyClass {
如果JVM并没有打乱属性的声明顺序,其对象内存布局将会是下面这个样子:
[padding: 3 bytes] 12
4 bytes] 16
1 byte ] 17
[padding: 7 bytes] 24
8 bytes] 32
4 bytes] 36
[padding: 4 bytes] 40
此时,用于占位的14个字节是浪费的,这个对象一共使用了40个字节的内存空间。但是,如果用上面的规则对这些对象重新排序,其内存结果会变成下面这个样子:
8 bytes] 16
4 bytes] 20
1 byte ] 21
1 byte ] 22
[padding: 2 bytes] 24
4 bytes] 28
[padding: 4 bytes] 32
这次,用于占位的只有6个字节,这个对象使用了32个字节的内存空间。
因此,对象内存布局的第二个规则是:
规则2:类属性按照如下优先级进行排列:长整型和双精度类型;整型和浮点型;字符和短整型;字节类型和布尔类型,最后是引用类型。这些属性都按照各自的单位对齐。
现在我们知道如何计算一个继承了Object的类的实例的内存大小了。下面这个例子用来做下练习: java.lang.Boolean。这是其内存布局:
[padding: 7 bytes] 16
Boolean类的实例占用16个字节的内存!惊讶吧?(别忘了最后用来占位的7个字节)。
继承其他类的子类的内存布局
JVM所遵守的下面3个规则用来组织有父类的类的成员。对象内存布局的规则3如下:
规则3:不同类继承关系中的成员不能混合排列。首先按照规则2处理父类中的成员,接着才是子类的成员。
举例如下:
class B extends A {
类B的实例在内存中的存储如下:
8 bytes] 16
4 bytes] 20
4 bytes] 24
8 bytes] 32
如果父类中的成员的大小无法满足4个字节这个基本单位,那么下一条规则就会起作用:
规则4:当父类中最后一个成员和子类第一个成员的间隔如果不够4个字节的话,就必须扩展到4个字节的基本单位。
举例如下:
[padding: 3 bytes] 12
1 byte ] 13
[padding: 3 bytes] 16
注意到成员a被扩充了3个字节以保证和成员b之间的间隔是4个字节。这个空间不能被类B使用,因此被浪费了。
最后一条规则在下面情况下用来节省一些空间:如果子类成员是长整型或双精度类型,并且父类并没有用完8个字节。
规则5:如果子类第一个成员是一个双精度或者长整型,并且父类并没有用完8个字节,JVM会破坏规则2,按照整形(int),短整型(short),字节型(byte),引用类型(reference)的顺序,向未填满的空间填充。
举例如下:
其内存布局如下:
[padding: 3 bytes] 12
2 bytes] 14
1 byte ] 15
[padding: 1 byte ] 16
8 bytes] 24
在第12字节处,类A“结束”的地方,JVM没有遵守规则2,而是在长整型之前插入一个短整型和一个字节型成员,这样可以避免浪费3个字节。
数组的内存布局
数组有一个额外的头部成员,用来存放“长度”变量。数组元素以及数组本身,跟其他常规对象同样,都需要遵守8个字节的边界规则。
下面是一个有3个元素的字节数组的内存布局:
12 bytes] 12
1 byte ] 13
1 byte ] 14
1 byte ] 15
1 byte ] 16
下面是一个有3个元素的长整型数字的内存布局:
12 bytes] 12
4 bytes] 16
8 bytes] 24
8 bytes] 32
8 bytes] 40
内部类的内存布局
(Non-static inner classes)有一个额外的“隐藏”成员,这个成员是一个指向外部类的引用变量。这个成员是一个普通引用,因此遵守引用内存布局的规则。内部类因此有4个字节的额外开销。
最后的一点想法
我们已经学习了在32位Sun JVM中如何计算Java对象的shallow size。知道内存是如何组织的有助于理解类实例占用的内存数。
下一篇文章中,会有些示例代码,这些代码会把相关内容整理到一起,用反射(reflection)来计算一个对象的deep size。如果你感兴趣,请或者等待这个博客的更新吧!
英文原文:,翻译: -
译文链接:
【如需转载,请在正文中标注并保留原文链接、译文链接和译者等信息,谢谢合作!】
原文链接:
- 译文链接: [ 转载请保留原文出处、译者和译文链接。]
关于作者:
2009年北航计算机学院毕业,加入IBM CDL至今。从事过web产品测试及开发工作。目前兴趣主要在游泳和自助穷游上。
可能感兴趣的文章
这么好的文章为什么没人评论呢
关于ImportNew
ImportNew 专注于 Java 技术分享。于日 11:11正式上线。是的,这是一个很特别的时刻 :)
ImportNew 由两个 Java 关键字 import 和 new 组成,意指:Java 开发者学习新知识的网站。 import 可认为是学习和吸收, new 则可认为是新知识、新技术圈子和新朋友……
新浪微博:
推荐微信号
反馈建议:@
广告与商务合作QQ:
– 好的话题、有启发的回复、值得信赖的圈子
– 写了文章?看干货?去头条!
– 为IT单身男女服务的征婚传播平台
– 优秀的工具资源导航
– 活跃 & 专业的翻译小组
– 国内外的精选博客文章
– UI,网页,交互和用户体验
– JavaScript, HTML5, CSS
– 专注Android技术分享
– 专注iOS技术分享
– 专注Java技术分享
– 专注Python技术分享
& 2017 ImportNew

我要回帖

更多关于 java 获得对象地址 的文章

 

随机推荐