在开发Java的过程中,怎么样来监测一个对象占用的内存大小,对于调试程序,优化程序来说,有很大的帮助,本文介绍了一个开发包,JAMM (Java Agent for Memory Measurements),可以很方便的在程序的运行过程中动态监测对象的内存占用情况。
This short article shows how to measure java object memory size at runtime with JAMM, a java agent dedicated to measure actual object memory use including JVM overhead.
JAMM uses the Instrumentation implementation provided by the JVM to compute memory usage of a given object by calling the getObjectSize(..) method.
It is quite simple to use, as explained by the author:
1 2 3 4 5 | MemoryMeter meter = new MemoryMeter(); meter.measure(object); meter.measureDeep(object); meter.countChildren(object); |
MemoryMeter meter = new MemoryMeter(); meter.measure(object); meter.measureDeep(object); meter.countChildren(object);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | < dependencies > < dependency > < groupid >junit</ groupid > < artifactid >junit</ artifactid > < version >4.11</ version > < scope >test</ scope > </ dependency > <!-- jamm java agent --> < dependency > < groupid >com.github.stephenc</ groupid > < artifactid >jamm</ artifactid > < version >0.2.5</ version > < scope >test</ scope > </ dependency > </ dependencies > < build > < plugins > <!-- copies java agent dependency into the target directory --> < plugin > < groupid >org.apache.maven.plugins</ groupid > < artifactid >maven-dependency-plugin</ artifactid > < version >2.8</ version > < executions > < execution > < id >copy-dependencies</ id > < phase >generate-test-resources</ phase > < goals > < goal >copy</ goal > </ goals > < configuration > < artifactitems > < artifactitem > < groupid >com.github.stephenc</ groupid > < artifactid >jamm</ artifactid > < version >0.2.5</ version > < type >jar</ type > < outputdirectory >${project.build.directory}</ outputdirectory > < destfilename >jamm.jar</ destfilename > </ artifactitem > </ artifactitems > </ configuration > </ execution > </ executions > </ plugin > <!-- executes test with java agent options of the JVM --> < plugin > < groupid >org.apache.maven.plugins</ groupid > < artifactid >maven-surefire-plugin</ artifactid > < version >2.14</ version > < configuration > < argline >-javaagent:${project.build.directory}/jamm.jar</ argline > </ configuration > </ plugin > </ plugins > </ build > |
< dependencies > < dependency > < groupid >junit</ groupid > < artifactid >junit</ artifactid > < version >4.11</ version > < scope >test</ scope > </ dependency > <!-- jamm java agent --> < dependency > < groupid >com.github.stephenc</ groupid > < artifactid >jamm</ artifactid > < version >0.2.5</ version > < scope >test</ scope > </ dependency > </ dependencies > < build > < plugins > <!-- copies java agent dependency into the target directory --> < plugin > < groupid >org.apache.maven.plugins</ groupid > < artifactid >maven-dependency-plugin</ artifactid > < version >2.8</ version > < executions > < execution > < id >copy-dependencies</ id > < phase >generate-test-resources</ phase > < goals > < goal >copy</ goal > </ goals > < configuration > < artifactitems > < artifactitem > < groupid >com.github.stephenc</ groupid > < artifactid >jamm</ artifactid > < version >0.2.5</ version > < type >jar</ type > < outputdirectory >${project.build.directory}</ outputdirectory > < destfilename >jamm.jar</ destfilename > </ artifactitem > </ artifactitems > </ configuration > </ execution > </ executions > </ plugin > <!-- executes test with java agent options of the JVM --> < plugin > < groupid >org.apache.maven.plugins</ groupid > < artifactid >maven-surefire-plugin</ artifactid > < version >2.14</ version > < configuration > < argline >-javaagent:${project.build.directory}/jamm.jar</ argline > </ configuration > </ plugin > </ plugins > </ build >
Next, write the following JUnit that explores the JAMM features:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | package org.javabenchmark.memory; import java.util.ArrayList; import java.util.List; import org.github.jamm.MemoryMeter; import org.junit.Test; public class MemoryMeterTest { private MemoryMeter meter = new MemoryMeter(); @Test public void shouldMeasureMemoryUsage() { String st1 = "This is the string #1" ; measure(st1); String st2 = "This is the string #2 and it has more chars." ; measure(st2); List aList = new ArrayList( 0 ); measure(aList); aList.add(st1); measure(aList); aList.add(st2); measure(aList); } private void measure(Object anObject) { System.out.println( "-----------------------------------" ); System.out.printf( "size: %d bytes\n" , meter.measure(anObject)); System.out.printf( "retained size: %d bytes\n" , meter.measureDeep(anObject)); System.out.printf( "inner object count: %d\n" , meter.countChildren(anObject)); } } |
package org.javabenchmark.memory; import java.util.ArrayList; import java.util.List; import org.github.jamm.MemoryMeter; import org.junit.Test; public class MemoryMeterTest { private MemoryMeter meter = new MemoryMeter(); @Test public void shouldMeasureMemoryUsage() { String st1 = "This is the string #1" ; measure(st1); String st2 = "This is the string #2 and it has more chars." ; measure(st2); List aList = new ArrayList( 0 ); measure(aList); aList.add(st1); measure(aList); aList.add(st2); measure(aList); } private void measure(Object anObject) { System.out.println( "-----------------------------------" ); System.out.printf( "size: %d bytes\n" , meter.measure(anObject)); System.out.printf( "retained size: %d bytes\n" , meter.measureDeep(anObject)); System.out.printf( "inner object count: %d\n" , meter.countChildren(anObject)); } }
Running the test produces the following output on my computer:
----------------------------------- size: 24 bytes retained size: 88 bytes inner object count: 2 ----------------------------------- size: 24 bytes retained size: 128 bytes inner object count: 2 ----------------------------------- size: 24 bytes retained size: 40 bytes inner object count: 2 ----------------------------------- size: 24 bytes retained size: 136 bytes inner object count: 4 ----------------------------------- size: 24 bytes retained size: 264 bytes inner object count: 6
To conclude, you can see how it is easy to monitor the memory usage of your objects. It is very handy when dealing with huge collections, or when using caches such as the ones provided by Guava or EHCache. That way you can setup trigger that alert when memory consumption is excessive.
注意:
如果在调试的过程中,发现内存不足的情况,请调整JVM的启动参数。
JVM options: -Xms256m -Xmx256m.