- 浏览: 134132 次
- 性别:
- 来自: 长沙->杭州
文章分类
- 全部博客 (39)
- 《Java面向对象设计最佳实践 》 (6)
- Software Architecture (0)
- Hardware Architecture (0)
- Software Engine (2)
- Article (1)
- Presentation (1)
- Miscellaneous (10)
- HotSpot JVM (1)
- 《深入Java并发》 (2)
- Java Core (2)
- Psychology (0)
- Java EE (6)
- Database (0)
- Performance Tuning (0)
- Troubleshotting (0)
- Web (0)
- Source Code (0)
- Open Source (0)
- Linux (0)
- NoSQL (2)
- Programming Languages (1)
- C/C++ (0)
- ASM (0)
- Advertisement (3)
- Principles of Management (0)
- asdasd (0)
- Test (0)
最新评论
-
hanmiao:
谢谢分享,上周遇到了壹个和 java.protocol.han ...
Java URL协议扩展实现 -
javatozhang:
没有细细的研究过URL类,文章不错!
Java URL协议扩展实现 -
bin_1715575332:
呵呵,很好的文章,这方面的文章不多啊。
Java URL协议扩展实现 -
hongli911:
extends被译成扩展????不是继承么?我呵呵
JSP自定义标签学习(基础) -
littlecar:
这个。。啥时候出来哈
《深入Java并发》- 目录(v0.1)
在大规模Java 应用开发中,总会遇到内存泄漏的问题。通常的做法,通过 Profile 工具,分析 Java Heap ,一般能够发现哪些对象内存占用巨大,而引起的泄漏问题。为了更好地深入了解问题的本质,以及从另外一个角度来分析问题,特写这篇文章。
可能不少的读者,并不清楚Java 对象到底占居多少的空间(单位:字节 =8 比特)。文章中会使用 JDK 6 update 7 自带的 Profile 工具 -Java VisualVM 。引入 Profile 工具的目的正是为了分析对象的大小。
首先,要区别Java 对象和 Java 类元信息,其中, JVM 把所有的 Java 对象放到 Java Heap 中,而类的元信息是放在方法区的,通俗地说,在 Java 源代码中,定义的字段和方法等变量标示(比如字段名称和类型等)。请注意,元信息所引用的对象还是在 Java Heap 里面。那么,本章主要 针对 的是Java Heap 。
早几天,看到了JavaEye 上面提问 -http://www.iteye.com/problems/45423 。问题的本质,和主题一样,不过它想要通过 Java 程序来计算,貌似有点困难。以前外国一个哥们( http://www.javaworld.com/javaworld/javatips/jw-javatip130.html )也写 个 一个程序计算对象大小,它的计算如下:
public class Sizeof
{
public static void main (String [] args) throws Exception
{
// Warm up all classes/methods we will use
runGC ();
usedMemory ();
// Array to keep strong references to allocated objects
final int count = 100000;
Object [] objects = new Object [count];
long heap1 = 0;
// Allocate count+1 objects, discard the first one
for (int i = -1; i < count; ++ i)
{
Object object = null;
// Instantiate your data here and assign it to object
object = new Object ();
if (i >= 0)
objects [i] = object;
else
{
object = null; // Discard the warm up object
runGC ();
heap1 = usedMemory (); // Take a before heap snapshot
}
}
runGC ();
long heap2 = usedMemory (); // Take an after heap snapshot:
final int size = Math.round (((float)(heap2 - heap1))/count);
System.out.println ("'before' heap: " + heap1 +
", 'after' heap: " + heap2);
System.out.println ("heap delta: " + (heap2 - heap1) +
", {" + objects [0].getClass () + "} size = " + size + " bytes");
for (int i = 0; i < count; ++ i) objects [i] = null;
objects = null;
}
private static void runGC () throws Exception
{
// It helps to call Runtime.gc()
// using several method calls:
for (int r = 0; r < 4; ++ r) _runGC ();
}
private static void _runGC () throws Exception
{
long usedMem1 = usedMemory (), usedMem2 = Long.MAX_VALUE;
for (int i = 0; (usedMem1 < usedMem2) && (i < 500); ++ i)
{
s_runtime.runFinalization ();
s_runtime.gc ();
Thread.currentThread ().yield ();
usedMem2 = usedMem1;
usedMem1 = usedMemory ();
}
}
private static long usedMemory ()
{
return s_runtime.totalMemory () - s_runtime.freeMemory ();
}
private static final Runtime s_runtime = Runtime.getRuntime ();
} // End of class
( 代码 1)
通过改变红色区域,来切换测试对象。先运行出结果,以下结果是在Windows XP x86 ,SUN JDK 1.6.0 update 7 ,并且Console 信息部分被截断:
{class java.lang.Object} size = 8 bytes
{class java.lang.Integer} size = 16 bytes
{class java.lang.Long} size = 16 bytes
{class java.lang.Byte} size = 16 bytes
{class [Ljava.lang.Object;} size = 16 bytes //长度为0的Object类型数组
{class [Ljava.lang.Object;} size = 16 bytes //长度为1的Object类型数组
{class [Ljava.lang.Object;} size = 24 bytes //长度为2的Object类型数组
现在,这个结论有问题,因为,从Byte、Long、Integer源代码的角度,不可能对象空间大小相同,那么接下来需要借助于Java VisualVM来做了。 在测试之前 ,需要一段辅助程序,帮助执行。实现如下:
public class MainClass {
/**
* 启动方法
* @param args
*/
public static void main(String[] args) throws Exception {
Object object = new Object();
neverStop ();
neverGC (object);
}
private static void neverGC(Object object) {
System. out .println(object);
}
private static void neverStop() throws InterruptedException {
Thread. sleep (Long. MAX_VALUE );
}
}
( 代码2 )
这个程序保证对象不会被GC掉,并且不会停止。
首先,在Java VisualVM上面,选择正确的程序进行监控,然后做一个Heap Dump。
(图1)
Dump之后,点击 Classes ,然后过滤出 java.lang.Object ,如图所示:
(图2)
(图3)
图 3中 过滤出三个结果,暂时不看数组对象,选择java.lang.Object ,然后点击 instances 按钮,或者双击 java.lang.Object 。
( 图 4)
结果发现,Object 对象的大小总是 8 个字节。再看看 Integer 、 Long 和 Byte 。 Sizeof 类的计算结果不可信,分析错误原因放一下,后面会提到。先来分析 Integer 、 Long 和 Byte 。从源代码的角度来分析, Integer 包含了一个 int 的 value, 其他的也有对应类型。而知晓, int 占用 4 个字节, long 则是 8 个字节, byte 占用 1 个字节。看图说话:
(图5)
(图6)
(图7)
Integer对象空间大小是 12 字节(见图 5) , Long 对象空间则是 16 个字节(见图 6 ), Byte 空间则是 9 个字节(见图 7 )。那么除去对象自身的状态 value ,得出的结论是,最后“空壳”对象都 8 字节?不能确定,因为还有类(静态)字段没有考虑,这些字段是否属于对象实例的一部分呢?很多书上面再三强调类的字段不属于对象实例,对于这种说法需要保持怀疑的态度?下面做一个“空壳”对象实验,代码如下:
/**
* 和Object一样,没有任何添加对象状态。
* @author mercy
*/
public class SameAsObject extends Object {
}
( 代码3 )
修改 MainClass程序, new 一个 SameAsObject 对象,重新 Heap Dump,结果图:
(图8)
图8 中表明,证明了“空壳”对象空间大小 8 字节,和 java.lang.Object 类似。目前还不能证明 Integer 的情况,因为 Integer 类的层次是 Integer <- Number <- Object 。虽然 Number 没有对象状态,可是也不能证明出去 value 的 Integer 对象空间大小等于 Object 的。为了证明这一点,再扩展一下 SameAsObject, 使其成为父类,创建一个子类 ExtSameAsObject 。同样的方法,获取大小:
(图9)
图9 中, ExtSameAsObject 的空间大小还是 8 字。 证明了空壳对象大小等同于java.lang.Object 的。 那么自然地可以推导出java.lang.Double 也是 16 字节( 8 字节空壳对象 +8 字节的 double 类型 value) 。
细心的读者会发现,图8 和 9 中,笔者标记了红色区域,都有 Java frame 的标识。而在MainClass 的 main 方法中,有一句: Object object = new ExtSameAsObject(); 这个对象是局部变量。说明什么问题呢? 两个问题:第一,正因为在方法内部执行,这个语句就是一个 frame,而 frame 是 Java Stack 的组成单位。这个 frame 被压入栈,并且类型是 ExtSameAsObject ,同时带有一个对象的地址 #1 (当然这里不是实际地址,只是一个引用标识)。第二,即使是局部对象,对象仍然分配在 Java Heap 中。
既然“空壳”的Integer 对象,占用 8 个字节的大小,那么类的成员就不应该归入对象实例之中。从实验中,我们可以得出结论, 某个类的任何类成员的常量和变量,都不会分配(或计算)到该类的对象实例。
回到Sizeof 类,为什么 Sizeof 会计算出问题?虽然 Sizeof 类计算有误,不过它的思想还是几点值得借鉴:
第一、 作者深入了了解了Runtime#gc() 方法和 Runtime#runFinalization 方法的语义。这两个方法并不是实时执行,而是建议 JVM 执行,执行与否程序怎么知道呢 ? 在— _runGC 方法中,作者试图通过内存的变化来判断是否 GC ( GC 后,肯定会变化的),确实有道理。
第二、 通过N 次,求得平均数,比单次测试要精确很多。
第三、 没有开辟其他对象,不影响结果。
同时,不过作者忽略了如下情况:
第一、 GC不只是针对需要测试的对象,而是整个 JVM 。因此在 GC 的时候,有可能是 JVM 启动后,把其他没有使用的对象给 GC 了,这样造成了使用空间的变大,而 Heap 空间变小。
第二、 Runtime#freeMemory()方法,返回的数据是 近视值 ,不一定能够保证正确性。因此在后面的累计、求平均数来带了误差。
第三、 使用了Math#round() 方法,又带来了误差。
由于Sizeof 的不精确,不能作为测试基准。
那么,更多的疑问产生了。前面测试的都是单一对象,那么数组对象是如何分配的?
修改程序如下:
public static void main(String[] args) throws Exception {
//Object object = new ExtSameAsObject();
Object [] object = new Object [0];
...
( 代码4 )
重新Heap Dump:
(图10)
余下内容,看附件。错误内容已经修正,请下载Fix1文档 。
- Dive_in_Java_Object_size_fix_1_.zip (270.8 KB)
- 下载次数: 642
评论
写得不错,让我萌生了一个想法-递归计算空间大小。
发现这个代码还需要做大改动,有时候多个对象共享一个成员变量,还有时,一个对象循环引用自己:
public class A{
A a = this;
}
更糟糕的是,刚发现的
不同的JVM,内存管理不一样, 导致一个引用的大小有可能不同,相同长度的数组占用的空间也有可能不同。
(1).32位和64位的JVM有不同
(2).不同厂商的相同位数的JVM也有不同
(3).相同厂商不同版本的JVM,如1.5,1.6的。。。也有可能不同
引用大小:SUN的32位JVM,4字节,SUM的64位JVM,8字节,JRockit的32位/64位JVM,引用都是4字节
另外JVM在server模式下的System.gc()方法难以生效,测试时要在client模式下测
以上这些还是已知的,还有未知的不同。。。。。
嗯,因此Profile工具是必要的,程序写的东西,不确定因素很多。
写得不错,让我萌生了一个想法-递归计算空间大小。
发现这个代码还需要做大改动,有时候多个对象共享一个成员变量,还有时,一个对象循环引用自己:
public class A{
A a = this;
}
更糟糕的是,刚发现的
不同的JVM,内存管理不一样, 导致一个引用的大小有可能不同,相同长度的数组占用的空间也有可能不同。
(1).32位和64位的JVM有不同
(2).不同厂商的相同位数的JVM也有不同
(3).相同厂商不同版本的JVM,如1.5,1.6的。。。也有可能不同
引用大小:SUN的32位JVM,4字节,SUM的64位JVM,8字节,JRockit的32位/64位JVM,引用都是4字节
另外JVM在server模式下的System.gc()方法难以生效,测试时要在client模式下测
以上这些还是已知的,还有未知的不同。。。。。
这个我认了,大家都是高手!
民主就是这么来的!
这个代码在符合我的电脑(64位CPU,装32位操作系统,32位sun的虚拟机)的内存使用情况。
我电脑内存使用情况是拿gc()后的内存增长量做测试的。
import java.lang.reflect.*; //一个引用:4字节 //一个Object:8字节 //一个Integer:16字节 == (8 + 4) / 8 * 8 //一个int:4字节 //长度l的byte数组:(l+19)/8*8 //长度l的char/short数组:(l*2+19)/8*8 == (l+9)/4*8 //长度l的String:(l+1)/4*8+40 //长度l的int数组:(l*4+19)/8*8 ==(l+4)/2*8 //长度l的long数组:(l*8+19)/8*8 == (l+2)*8 public class Occupy { //不写不行... public static int occupyof(boolean variable) {return 1;} public static int occupyof(byte variable) {return 1;} public static int occupyof(short variable) {return 2;} public static int occupyof(char variable) {return 2;} public static int occupyof(int variable) {return 4;} public static int occupyof(float variable) {return 4;} public static int occupyof(long variable) {return 8;} public static int occupyof(double variable) {return 8;} public static int occupyof(Object object) { if (object == null) return 0; int size = 8; Class clazz = object.getClass(); if (clazz.isArray()) { size = 4;//length变量是int型 Class<?> componentType = clazz.getComponentType(); if (componentType.isPrimitive()) return occupyofSize(size + lengthOfPrimitiveArray(object) * sizeofPrimitiveClass(componentType)); Object[] array = (Object[]) object; size += 4 * array.length; for (Object o : array) size += occupyof(o); return occupyofSize(size); } Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { if (Modifier.isStatic(field.getModifiers())) continue;//类成员不计 Class<?> type = field.getType(); if (type.isPrimitive()) size += sizeofPrimitiveClass(type); else { size += 4;//一个引用型变量占用4个字节 try { field.setAccessible(true);//可以访问非public类型的变量 size += occupyof(field.get(object)); } catch (Exception e) { size += occupyofConstructor(object, field); } } } return occupyofSize(size); } public static int sizeof(boolean variable) {return 1;} public static int sizeof(byte variable) {return 1;} public static int sizeof(short variable) {return 2;} public static int sizeof(char variable) {return 2;} public static int sizeof(int variable) {return 4;} public static int sizeof(float variable) {return 4;} public static int sizeof(long variable) {return 8;} public static int sizeof(double variable) {return 8;} public static int sizeof(Object object) { if (object == null) return 0; int size = 8; Class clazz = object.getClass(); if (clazz.isArray()) { size = 4;//length变量是int型 Class<?> componentType = clazz.getComponentType(); if (componentType.isPrimitive()) return size + lengthOfPrimitiveArray(object) * sizeofPrimitiveClass(componentType); Object[] array = (Object[]) object; size += 4 * array.length; for (Object o : array) size += sizeof(o); return size; } Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { if (Modifier.isStatic(field.getModifiers())) continue;//类成员不计 Class<?> type = field.getType(); if (type.isPrimitive()) size += sizeofPrimitiveClass(type); else { size += 4;//一个引用型变量占用4个字节 try { field.setAccessible(true);//可以访问非public类型的变量 size += sizeof(field.get(object)); } catch (Exception e) { size += sizeofConstructor(object, field); } } } return size; } private static int occupyofConstructor(Object object, Field field) { throw new UnsupportedOperationException("field type Contructor not accessible: " + object.getClass() + " field:" + field); } private static int sizeofConstructor(Object object, Field field) { throw new UnsupportedOperationException("field type Contructor not accessible: " + object.getClass() + " field:" + field); } /** * 对象的大小 和 占用空间并不相等,就好象Windows下文件一样(大小为1字节时占用空间4k) * 对象占用空间的增长以8个字节为单位,占用空间=大小对8的无条件进位法, * 即occupy = (size + 8 - 1) / 8 * 8; 例如: * 大小8字节:占用8字节,(new Object()就是占用8字节) * 大小9字节:占用16字节 * 大小16字节:占用16字节 * 大小17字节:占用24字节 * @param size 大小,以字节为单位 * @return 占用空间 */ private static int occupyofSize(int size) { return (size + 7) / 8 * 8; } private static int sizeofPrimitiveClass(Class clazz) { return clazz == boolean.class || clazz == byte.class ? 1 : clazz == char.class || clazz == short.class ? 2 : clazz == int.class || clazz == float.class ? 4 : 8; } private static int lengthOfPrimitiveArray(Object object) { Class<?> clazz = object.getClass(); return clazz == boolean[].class ? ((boolean[]) object).length : clazz == byte[].class ? ((byte[]) object).length : clazz == char[].class ? ((char[]) object).length : clazz == short[].class ? ((short[]) object).length : clazz == int[].class ? ((int[]) object).length : clazz == float[].class ? ((float[]) object).length : clazz == long[].class ? ((long[]) object).length : ((double[]) object).length; } public static void main(String[] args) throws Throwable { System.out.println(occupyof(new String("Web.Zhu"))); } }
写得不错,让我萌生了一个想法-递归计算空间大小。
这个代码在符合我的电脑(64位CPU,装32位操作系统,32位sun的虚拟机)的内存使用情况。
我电脑内存使用情况是拿gc()后的内存增长量做测试的。
import java.lang.reflect.*; //一个引用:4字节 //一个Object:8字节 //一个Integer:16字节 == (8 + 4 + 7) / 8 * 8 //一个int:4字节 //长度l的byte数组:(l+19)/8*8 //长度l的char/short数组:(l*2+19)/8*8 == (l+9)/4*8 //长度l的String:(l+1)/4*8+40 //长度l的int数组:(l*4+19)/8*8 ==(l+4)/2*8 //长度l的long数组:(l*8+19)/8*8 == (l+2)*8 public class Occupy { //不写不行... public static int occupyof(boolean variable) {return 1;} public static int occupyof(byte variable) {return 1;} public static int occupyof(short variable) {return 2;} public static int occupyof(char variable) {return 2;} public static int occupyof(int variable) {return 4;} public static int occupyof(float variable) {return 4;} public static int occupyof(long variable) {return 8;} public static int occupyof(double variable) {return 8;} public static int occupyof(Object object) { if (object == null) return 0; int size = 8;//对象本身8字节 Class clazz = object.getClass(); if (clazz.isArray()) { size += 4;//length变量是int型 Class<?> componentType = clazz.getComponentType(); if (componentType.isPrimitive()) return occupyofSize(size + lengthOfPrimitiveArray(object) * sizeofPrimitiveClass(componentType)); Object[] array = (Object[]) object; size += 4 * array.length; for (Object o : array) size += occupyof(o); return occupyofSize(size); } Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { if (Modifier.isStatic(field.getModifiers())) continue;//类成员不计 Class<?> type = field.getType(); if (type.isPrimitive()) size += sizeofPrimitiveClass(type); else { size += 4;//一个引用型变量占用4个字节 try { field.setAccessible(true);//可以访问非public类型的变量 size += occupyof(field.get(object)); } catch (Exception e) { size += occupyofConstructor(object, field); } } } return occupyofSize(size); } public static int sizeof(boolean variable) {return 1;} public static int sizeof(byte variable) {return 1;} public static int sizeof(short variable) {return 2;} public static int sizeof(char variable) {return 2;} public static int sizeof(int variable) {return 4;} public static int sizeof(float variable) {return 4;} public static int sizeof(long variable) {return 8;} public static int sizeof(double variable) {return 8;} public static int sizeof(Object object) { if (object == null) return 0; int size = 8; Class clazz = object.getClass(); if (clazz.isArray()) { size = 4;//length变量是int型 Class<?> componentType = clazz.getComponentType(); if (componentType.isPrimitive()) return size + lengthOfPrimitiveArray(object) * sizeofPrimitiveClass(componentType); Object[] array = (Object[]) object; size += 4 * array.length; for (Object o : array) size += sizeof(o); return size; } Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { if (Modifier.isStatic(field.getModifiers())) continue;//类成员不计 Class<?> type = field.getType(); if (type.isPrimitive()) size += sizeofPrimitiveClass(type); else { size += 4;//一个引用型变量占用4个字节 try { field.setAccessible(true);//可以访问非public类型的变量 size += sizeof(field.get(object)); } catch (Exception e) { size += sizeofConstructor(object, field); } } } return size; } private static int occupyofConstructor(Object object, Field field) { throw new UnsupportedOperationException("field type Contructor not accessible: " + object.getClass() + " field:" + field); } private static int sizeofConstructor(Object object, Field field) { throw new UnsupportedOperationException("field type Contructor not accessible: " + object.getClass() + " field:" + field); } /** * 对象的大小 和 占用空间并不相等,就好象Windows下文件一样(大小为1字节时占用空间4k) * 对象占用空间的增长以8个字节为单位,占用空间=大小对8的无条件进位法, * 即occupy = (size + 8 - 1) / 8 * 8; 例如: * 大小8字节:占用8字节,(new Object()就是占用8字节) * 大小9字节:占用16字节 * 大小16字节:占用16字节 * 大小17字节:占用24字节 * @param size 大小,以字节为单位 * @return 占用空间 */ private static int occupyofSize(int size) { return (size + 7) / 8 * 8; } private static int sizeofPrimitiveClass(Class clazz) { return clazz == boolean.class || clazz == byte.class ? 1 : clazz == char.class || clazz == short.class ? 2 : clazz == int.class || clazz == float.class ? 4 : 8; } private static int lengthOfPrimitiveArray(Object object) { Class<?> clazz = object.getClass(); return clazz == boolean[].class ? ((boolean[]) object).length : clazz == byte[].class ? ((byte[]) object).length : clazz == char[].class ? ((char[]) object).length : clazz == short[].class ? ((short[]) object).length : clazz == int[].class ? ((int[]) object).length : clazz == float[].class ? ((float[]) object).length : clazz == long[].class ? ((long[]) object).length : ((double[]) object).length; } public static void main(String[] args) throws Throwable { System.out.println(occupyof(new String("Web.Zhu"))); } }
64位的话 就是8字节一单元了
好文章,写的不错
看来使用的时候要多注意了。
确实,我们项目中解决的办法就是加些限制条件
比如说从数据库中查询几万条数据放到list里面
但是又不知道那个对象到底能装多少,所有只有加限制条件,一次少装点了。
hotspot/src/share/vm/classfile/classFileParser.cpp
找这个方法:
ClassFileParser::parseClassFile(),看2833行开始:
// Field size and offset computation
对象布局的计算就在里面,包括instanceKlass自身的布局(包含有Java类的静态变量)和Java对象实例的布局都在这里算。
谢谢,尽管我没有过(最近也在研究JVM实现),但是我比较偏好HotSpot的实现。不过我打算再写一篇计算篇,通过反向推到出来。
hotspot/src/share/vm/classfile/classFileParser.cpp
找这个方法:
ClassFileParser::parseClassFile(),看2833行开始:
// Field size and offset computation
对象布局的计算就在里面,包括instanceKlass自身的布局(包含有Java类的静态变量)和Java对象实例的布局都在这里算。
原因是32位HotSpot的对象分配是8字节对齐的。当对象自身所需数据占不足8字节的倍数的时候就会在一些位置加上padding。“一些位置”一般是整个对象的末尾,也可能是在中间。
HotSpot是按成员类型来计算对象布局的。可以读一下这篇,讲得还不错:Java Objects Memory Structure
(看不到的话请自行想办法翻……)
这帖讲的内容适用于32位HotSpot。其它JVM则有各自不同的对象布局方式。例如说早期的Sun JVM(后来叫Classic VM)采用的对象布局就跟HotSpot的完全不同,而像SableVM采用的对象布局则相当有特色。JVM规范并没有对对象布局做定义——JVM实现可以用自己喜欢的方式来做。
要靠谱的Java对象大小数据,可以参考这帖使用JVMTI来获取:Again about determining size of Java object
VisualVM也是通过JVMTI来获取对象大小、数量等的信息。
以前我也发过一帖是拿32位HotSpot的对象布局来玩的,[标题党] 跑得好好的C#程序咋移植为Java就不够内存用了呢?——忽悠一把
如果你只是问JVM中一个 new object的大小,其实我也不知道
可以计算的,只是在x86和x64上面有不同而已,不然Profile工具就是失去了意义。
从JVM实现的角度,统一了对象大小。
我没说清楚
你这个是用jprofile计算出来的,如果你那IBM VM看的话,可能就不一样。再次不同的VM版本,对象的大小也不一样。
我们在日常使用过程中,我自己只能估算一下,开多少数组,耗费多少内存。那究竟包含数组的对象耗费多少heap,你是不能计算出来的,除非拿jprofile等工具去实际测。
对于不同的JVM的实现,这个没有关系,最多是多测试而已。
如果你只是问JVM中一个 new object的大小,其实我也不知道
可以计算的,只是在x86和x64上面有不同而已,不然Profile工具就是失去了意义。
从JVM实现的角度,统一了对象大小。
我没说清楚
你这个是用jprofile计算出来的,如果你那IBM VM看的话,可能就不一样。再次不同的VM版本,对象的大小也不一样。
我们在日常使用过程中,我自己只能估算一下,开多少数组,耗费多少内存。那究竟包含数组的对象耗费多少heap,你是不能计算出来的,除非拿jprofile等工具去实际测。
如果你只是问JVM中一个 new object的大小,其实我也不知道
可以计算的,只是在x86和x64上面有不同而已,不然Profile工具就是失去了意义。
从JVM实现的角度,统一了对象大小。
如果你只是问JVM中一个 new object的大小,其实我也不知道
相关推荐
本文将深入探讨如何计算Java对象的大小,以及这个知识点在实际开发中的应用。 首先,Java对象的大小不仅仅包括其字段的大小,还包括对象头(object header)的大小,对于HotSpot虚拟机,它包含了对齐填充、Mark ...
本文将深入探讨如何计算Java对象所占内存,并通过提供的代码示例进行详细解析。 首先,我们需要理解Java对象内存占用的基本原理。每个Java对象都由三部分组成:对象头(Object Header)、实例数据(Instance Data)...
本篇文章将深入探讨如何计算Java对象占用的内存字节数,以及影响这一数值的因素。 首先,Java对象在堆内存中由四个部分组成:对象头(A)、基本类型域(B)、引用类型域(C)和填充物(D)。 **对象头(A)**: ...
本文将深入探讨如何统计缓存(尤其是Java对象)所占的内存大小,以及这对理解程序内存消耗的重要性。 首先,我们要知道Java对象的内存开销主要由三部分组成:对象头、实例数据和对齐填充。对象头包含对象的类型信息...
### 深入Java对象及元素的存储区域 在Java平台进行软件开发的过程中,一个显著的特点是对象的创建是在程序运行时动态发生的。这也就意味着,直到程序执行时才能最终确定对象应该存放在哪个内存区域。不同的存储区域...
例如,`sun.misc.Unsafe`类(虽然非标准,但广泛使用)提供了访问内存的能力,包括获取对象大小。然而,需要注意的是,这个类在Java 9及以后的版本中被弃用,并且在某些JRE中可能不可用。 `SizeOfObject.java`可能...
本篇文章将深入探讨Java对象池的实现原理,以及如何借鉴"Jakarta Commons Pool"组件来设计一个轻量级的对象池。 一、对象池的基本概念 对象池的基本工作流程包括以下几个步骤: 1. 初始化:预创建一定数量的对象并...
本文将深入探讨Java中的对象内存占用,以及如何使用"java-sizeof-0.0.4"工具来查看Java对象在内存中的大小。 在Java中,内存主要分为堆内存(Heap)和栈内存(Stack)。对象通常存储在堆内存中,而基本类型的变量和...
本文将详细阐述Java对象的创建过程,帮助读者深入理解Java基础。 #### 一、类加载机制 在Java中,对象是由类来创建的。因此,在创建任何对象之前,Java虚拟机(JVM)必须先找到对应的类文件(`.class` 文件),并...
《深入Java虚拟机(原书第2版)》,原书名《Inside the Java Virtual Machine,Second Edition》,作者:【美】Bill Venners,翻译:曹晓钢、蒋靖,出版社:机械工业出版社,ISBN:7111128052,出版日期:2003 年 9 ...
本篇文章将深入探讨Java对象在JVM内存中的布局,帮助我们理解JVM是如何存储和管理对象的。 首先,我们要知道JVM内存主要分为以下几个区域: 1. **堆内存(Heap)**:这是Java对象的主要存储区域,所有通过`new`...
《深入JAVA虚拟机第二版》是由Bill Venners撰写,并由曹晓钢和蒋靖翻译的中文书籍。这本书是Java开发者必备的经典读物,它详细地解析了Java虚拟机(JVM)的工作原理,帮助读者深入理解Java程序的运行机制。尽管描述...
本篇文章将深入探讨Java中的对象、基础类型以及数据处理相关的工具类。 首先,让我们关注Java中的基础类型。Java有八种原始数据类型:byte、short、int、long、float、double、char和boolean。为了方便处理这些类型...
总的来说,理解Java对象的创建、内存分配和JVM的工作机制对于编写高效、健壮的Java代码至关重要。这涉及到堆内存管理、对象生命周期、垃圾收集以及各种JVM优化策略。开发者应时刻关注这些细节,以便在解决性能问题时...
《深入Java虚拟机》这本书是IT领域中关于Java虚拟机(JVM)的深度解析之作,主要聚焦于JVM的工作原理、内部结构以及优化技巧。Java虚拟机作为Java语言的核心组件,其性能直接影响到Java应用程序的运行效率。因此,对...
### 优化Java堆大小的五个技巧详解 #### 一、JVM:理解基本原理与内存管理 ##### **1.1 JVM内存模型** JVM内存管理是Java开发人员必须掌握的基本概念之一,它不仅关系到应用的性能,还直接影响到系统的稳定性和...
在Java编程语言中,理解栈(stack)和堆(heap)的概念及其工作原理对于深入掌握Java虚拟机(JVM)如何管理内存至关重要。栈和堆都是在RAM中用于存储数据的关键区域,但在功能、使用场景和管理机制上存在显著差异。 #### ...
Java对象池是一种优化资源管理的技术,它通过复用已经创建并初始化过的对象,避免了频繁地创建和销毁对象带来的性能开销。在Java中,对象池通常用于数据库连接、线程、Socket等昂贵资源的管理。下面我们将深入探讨...
这个“Java内存使用系列一Java对象的内存占用”主题旨在深入探讨Java对象在内存中的表现,以及如何有效地管理这些资源。Java开发人员需要理解内存分配、垃圾回收机制以及如何避免内存泄漏,以确保程序的高效运行。 ...
《深入Java虚拟机(原书第二版清晰版)》这本书是为那些已经学习了Java编程语言,希望通过深入理解Java虚拟机(JVM)来进一步提升自己技术能力的Java程序员所准备的。本书详细介绍了JVM的内部工作机制,包括但不限于...