Java有一个很好的地方就是java的垃圾收集机制,这个机制集成于jvm的,对程序员来说是隐藏且不透明的。这种情况下,如何得到某个对象消耗的内存呢?
曾经看到过有人用以下方法来计算:在生成该object的前后都调用java.lang.Runtime.freeMemory()方法,然后看两者之差即为该object消耗的内存量。
这种方法的代码是:
<ccid_nobr></ccid_nobr>
<ccid_code><font size="4"><font color="#a52a2a">long totalMem = java.lang.Runtime.freeMemory();
Object myBigObject = null;
System.out.println("You just got rid of " + totalMem
- java.lang.Runtime.freeMemory());</font></font></ccid_code> |
这种想法是对的,但是实际上,jvm的freememory往往不能正确反应实际的free memory。比如在jvm要进行垃圾收集的时候,free memory就会缩小。而如果决定垃圾收集的时间发生在该object生成之后,而在第二次调用java.lang.Runtime.freeMemory()之前,那么就会错误地增加该object消耗的内存量。
在java专家By Tony Sintes的文章"Discover how much memory an object consumes " 里面提到了应该用Runtime.getRuntime().totalMemory();并且计算两次之差来得到消耗的内存量。
By Tony Sintes的源代码:
<ccid_nobr></ccid_nobr>
<ccid_code><font size="4"><font color="#a52a2a">public class Memory {
private final static int _SIZE = 500;
public static void main( String [] args )
throws Exception {
Object[] array = new Object[_SIZE];
Runtime.getRuntime().gc();
long start = Runtime.getRuntime().totalMemory();
for (int i = 0; i < _SIZE; i++) {
array[i] = new Object();
}
Runtime.getRuntime().gc();
long end = Runtime.getRuntime().totalMemory();
long difference = ( start - end ) / _SIZE;
System.out.println( difference + " bytes used
per object on average" );
}
}</font></font></ccid_code> |
实际上,这种方法基本上正确了,但是By Tony Sintes疏忽了一点,就是仅仅Runtime.getRuntime().gc();并不能真正完成垃圾收集,也就是说实际上jvm的内存此时并不是稳定的。
所以,只有当内存不再发生大的变动,或者说已经稳定,我们才可能说垃圾收集已经完成。
如何才能真正确保基本完成了jvm的垃圾收集呢?实现这个功能的代码如下:
<ccid_nobr></ccid_nobr>
<ccid_code><font size="4"><font color="#a52a2a">private static final Runtime s_runtime =
Runtime.getRuntime ();
private static long usedMemory ()
{
return s_runtime.totalMemory () -
s_runtime.freeMemory ();
}
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 ();
}
}</font></font></ccid_code> |
runGC()可以帮我们真正的确定完成垃圾收集(准确的说,应该说是基本上完成)。
分享到:
相关推荐
本文将深入探讨如何计算Java对象所占内存,并通过提供的代码示例进行详细解析。 首先,我们需要理解Java对象内存占用的基本原理。每个Java对象都由三部分组成:对象头(Object Header)、实例数据(Instance Data)...
本篇文章将深入探讨如何计算Java对象占用的内存字节数,以及影响这一数值的因素。 首先,Java对象在堆内存中由四个部分组成:对象头(A)、基本类型域(B)、引用类型域(C)和填充物(D)。 **对象头(A)**: ...
本文将深入探讨如何统计缓存(尤其是Java对象)所占的内存大小,以及这对理解程序内存消耗的重要性。 首先,我们要知道Java对象的内存开销主要由三部分组成:对象头、实例数据和对齐填充。对象头包含对象的类型信息...
本示例主要探讨如何测试Java对象占用的内存大小,以便更好地理解内存使用情况。 首先,`SizeOf.java`可能是一个实现自定义内存大小计算的类。在Java中,由于垃圾回收机制的存在,直接获取对象的内存占用并不像C++等...
当我们谈论“Java对象内存大小”时,我们通常指的是一个Java对象在内存中占据的空间,包括对象头、实例字段以及可能的对齐填充。这个知识点对于开发高效缓存系统尤其重要,因为缓存需要精确管理内存来最大化存储效率...
这篇博客文章可能探讨了如何通过不同的工具和技术来估算Java对象在内存中的占用空间。 首先,Java对象的大小不是固定不变的,它取决于对象的类结构,包括类中的属性数量、类型以及虚拟机的实现。每个对象都会有一个...
了解对象占用的内存大小有助于我们优化资源使用,减少内存泄漏,并提高程序效率。 "java-sizeof-0.0.4"是一个用于分析Java对象内存占用的工具,它可以帮助开发者更好地理解对象在运行时的内存消耗。这个工具提供了...
这个“Java内存使用系列一Java对象的内存占用”主题旨在深入探讨Java对象在内存中的表现,以及如何有效地管理这些资源。Java开发人员需要理解内存分配、垃圾回收机制以及如何避免内存泄漏,以确保程序的高效运行。 ...
### Java字符串内存计算 在Java开发中,理解内存管理至关重要,特别是对于字符串处理而言。本文将深入探讨如何在Java中计算字符串所占用的内存空间,包括现有的计算方法、其局限性以及具体的计算公式。 #### 计算...
一个空的String对象占用28个字节的内存,包含了一个指向字符数组的引用、一个偏移量、一个字符的长度和一个哈希码。当字符串内容非空时,内存占用会增加,因为需要存储字符数据。例如,字符串"ab"会占用28 + 2 * 2 =...
本文将深入探讨如何计算Java对象的大小,以及这个知识点在实际开发中的应用。 首先,Java对象的大小不仅仅包括其字段的大小,还包括对象头(object header)的大小,对于HotSpot虚拟机,它包含了对齐填充、Mark ...
本篇文章将深入探讨Java对象在JVM内存中的布局,帮助我们理解JVM是如何存储和管理对象的。 首先,我们要知道JVM内存主要分为以下几个区域: 1. **堆内存(Heap)**:这是Java对象的主要存储区域,所有通过`new`...
"计算对象占用内存空间ObjectSize-master.zip" 提供的工具可能是一个帮助开发者分析和估算对象在内存中占用大小的解决方案。这样的工具对于调试、性能调优以及避免内存泄漏至关重要。 在Java中,对象的内存占用不...
在Java中,程序员通常不需要手动管理内存,因为垃圾收集器会自动检测并释放不再使用的对象占用的内存,这减轻了程序员的工作负担,但同时也可能引入性能上的影响,如垃圾收集的开销。 理解Java对象在内存中的结构...
当一个对象不再被引用时,GC会自动回收该对象占用的内存,防止内存泄漏。 在Java中,对象的创建过程涉及内存分配和初始化。当我们使用`new`关键字创建对象时,首先在堆内存中为对象分配空间,然后调用构造函数初始...
总的来说,通过`sizeOf`计算Java对象的大小是一项复杂的工作,涉及到JVM内部的内存管理和对象表示。尽管Java API没有直接提供这样的功能,但我们可以借助第三方库或自定义工具来实现。理解对象大小对于优化内存使用...
### Java内存对象分配过程研究 #### 一、引言 Java作为一门强大的面向对象编程语言,在实际开发过程中,对象的创建及其内存管理是至关重要的环节。深入理解对象在内存中的分配过程不仅能够帮助开发者设计出更为...
本文介绍了在Java多线程环境下减少内存占用量的一些关键策略,包括线程生命周期管理、对象生命周期设计、同步机制选择、线程池的使用和线程数量控制。同时,代码的异常处理和JVM参数调优也是提升多线程应用性能的...
8、程序里不可避免大量使用字符串处理,避免使用 String,应大量使用StringBuffer,每一个 String 对象都得独立占用内存一块区域。 在使用字符串时,应该避免使用 String,而应该使用 StringBuffer,以免内存溢出。...