- 相關(guān)推薦
查看java對(duì)象所占的內(nèi)存大小的方法
做一些cache的時(shí)候,我們不可能把數(shù)據(jù)庫(kù)的所有的數(shù)據(jù)都緩存到內(nèi)存里面,我們要估計(jì)緩存的大小。那么如何查看java對(duì)象所占的內(nèi)存大小呢?本文為大家介紹一下方法,希望可以為您提供幫助!更多內(nèi)容請(qǐng)關(guān)注應(yīng)屆畢業(yè)生考試網(wǎng)!
。1)做一些cache的時(shí)候,我們不可能把數(shù)據(jù)庫(kù)的所有的數(shù)據(jù)都緩存到內(nèi)存里面,我們要估計(jì)緩存的大小。
(2)內(nèi)存泄露的時(shí)候,我們可以查看某些對(duì)象的大小來(lái)定位問(wèn)題,當(dāng)然還有其他的更有效的方式,比如使用MAT分析dump文件
(3)根據(jù)jvm的堆內(nèi)存設(shè)置,我們可以知道最多可以創(chuàng)建多少個(gè)對(duì)象。
從jdk5開(kāi)始,提供了Instrumentation API,它有一個(gè)叫做getObjectSize()的方法,但是,這個(gè)方法存在兩個(gè)問(wèn)題:
(1)不可以直接使用。必須要實(shí)現(xiàn)一個(gè)Instrumentation Agent,還得放到j(luò)ar包里面。
。2)它只能返回單個(gè)對(duì)象的大小,不能返回內(nèi)部包含的子對(duì)象的大小。
關(guān)于第一個(gè)問(wèn)題,很好解決,在任何一個(gè)類(lèi)里面聲明一個(gè)"premain"方法,就可以把這個(gè)類(lèi)做成是一個(gè)agent:
public class SizeOfAgent {
static Instrumentation inst;
/** initializes agent */
public static void premain(String agentArgs, Instrumentation instP) {
inst = instP;
}
}
jvm在啟動(dòng)的時(shí)候會(huì)調(diào)用premain()方法,同時(shí)會(huì)傳遞Instrumentation這個(gè)對(duì)象實(shí)例,要告訴jvm Instrumentation agent所在的類(lèi),需要把這個(gè)類(lèi)打到j(luò)ar包里面,
然后在manifest.mf這個(gè)文件設(shè)置一些屬性:
Premain-Class: sizeof.agent.SizeOfAgent
Boot-Class-Path:
Can-Redefine-Classes: false
java應(yīng)用在啟動(dòng)的時(shí)候,指定-javaagent參數(shù):
java -javaagent:sizeofag.jar <Your main class>
拿到Instrumentation這個(gè)實(shí)例以后,就可以調(diào)用sizeOf()方法了:
public class SizeOfAgent {
static Instrumentation inst;
// ...
public static long sizeOf(Object o) {
return inst.getObjectSize(o);
}
}
然后可以使用反射來(lái)獲取子對(duì)象的大小。
完整的代碼如下:
package com.bj58.test;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Stack;
public class SizeOfAgent {
static Instrumentation inst;
/** initializes agent */
public static void premain(String agentArgs, Instrumentation instP) {
inst = instP;
}
/**
* Returns object size without member sub-objects.
*
* @param o
* object to get size of
* @return object size
*/
public static long sizeOf(Object o) {
if (inst == null) {
throw new IllegalStateException(
"Can not access instrumentation environment.\n"
+ "Please check if jar file containing SizeOfAgent class is \n"
+ "specified in the java's \"-javaagent\" command line argument.");
}
return inst.getObjectSize(o);
}
/**
* Calculates full size of object iterating over its hierarchy graph.
*
* @param obj
* object to calculate size of
* @return object size
*/
public static long fullSizeOf(Object obj) {
Map<Object, Object> visited = new IdentityHashMap<Object, Object>();
Stack<Object> stack = new Stack<Object>();
long result = internalSizeOf(obj, stack, visited);
while (!stack.isEmpty()) {
result += internalSizeOf(stack.pop(), stack, visited);
}
visited.clear();
return result;
}
private static boolean skipObject(Object obj, Map<Object, Object> visited) {
if (obj instanceof String) {
// skip interned string
if (obj == ((String) obj).intern()) {
return true;
}
}
return (obj == null) // skip visited object
|| visited.containsKey(obj);
}
private static long internalSizeOf(Object obj, Stack<Object> stack,
Map<Object, Object> visited) {
if (skipObject(obj, visited)) {
return 0;
}
visited.put(obj, null);
long result = 0;
// get size of object + primitive variables + member pointers
result += SizeOfAgent.sizeOf(obj);
// process all array elements
Class clazz = obj.getClass();
if (clazz.isArray()) {
if (clazz.getName().length() != 2) {// skip primitive type array
int length = Array.getLength(obj);
for (int i = 0; i < length; i++) {
stack.add(Array.get(obj, i));
}
}
return result;
}
// process all fields of the object
while (clazz != null) {
Field[] fields = clazz.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
if (!Modifier.isStatic(fields[i].getModifiers())) {
if (fields[i].getType().isPrimitive()) {
continue; // skip primitive fields
} else {
fields[i].setAccessible(true);
try {
// objects to be estimated are put to stack
Object objectToAdd = fields[i].get(obj);
if (objectToAdd != null) {
stack.add(objectToAdd);
}
} catch (IllegalAccessException ex) {
assert false;
}
}
}
}
clazz = clazz.getSuperclass();
}
return result;
}
}
然后我們可以做一個(gè)測(cè)試:
public class Test {
static class Person{
private int id;
private String name;
private String address;
public Person(int id, String name, String address) {
this.id = id;
this.name = name;
this.address = address;
}
}
public static void main(String[] args) throws Exception {
Person p = new Person(12, "xujsh","bj");
long size = SizeOfAgent.fullSizeOf(p);
System.out.println(size);
}
}
切換到命令行:
D:\workspace\objsize\src>java -version
java version "1.6.0_22"
Java(TM) SE Runtime Environment (build 1.6.0_22-b04)
Java HotSpot(TM) Client VM (build 17.1-b03, mixed mode, sharing)
D:\workspace\objsize\src>javac com/bj58/test/*.java
D:\workspace\objsize\src>jar -cvfm size.jar MANIFEST.MF com/bj58/test/*
標(biāo)明清單(manifest)
增加:com/bj58/test/SizeOfAgent.class(讀入= 3119) (寫(xiě)出= 1698)(壓縮了 45%)
增加:com/bj58/test/SizeOfAgent.java(讀入= 3147) (寫(xiě)出= 1204)(壓縮了 61%)
增加:com/bj58/test/Test$Person.class(讀入= 442) (寫(xiě)出= 305)(壓縮了 30%)
增加:com/bj58/test/Test.class(讀入= 692) (寫(xiě)出= 441)(壓縮了 36%)
增加:com/bj58/test/Test.java(讀入= 509) (寫(xiě)出= 290)(壓縮了 43%)
D:\workspace\objsize\src>java -javaagent:size.jar com.bj58.test.Test
24
MANIFEST.MF:
Manifest-Version: 1.0
Main-Class: com.bj58.test.Test
Premain-Class: com.bj58.test.SizeOfAgent
Boot-Class-Path:
Can-Redefine-Classes: false
【注意】MANIFEST.MF文件的格式要求比較嚴(yán)格,每一行要滿足:key:空格value回車(chē)
\
如何在web應(yīng)用程序里面使用呢?
以我的tomcat為例,
(1)把size.jar上傳tomcat的lib目錄下面
(2)修改catalina.sh:
添加一行:
JAVA_OPTS="$JAVA_OPTS -javaagent:$CATALINA_HOME/lib/size.jar" //這一行是新添加的
if [ -z "$LOGGING_MANAGER" ]; then
JAVA_OPTS="$JAVA_OPTS -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager"
else
JAVA_OPTS="$JAVA_OPTS $LOGGING_MANAGER"
fi
(3)在應(yīng)用里面添加一個(gè)controler:
@Path(value = "/api/size")
@GET
public ActionResult size() {
Map<Long, List<Long>> map = ApiUtils.getHotindexBaidu();
long size = SizeOfAgent.fullSizeOf(map);
return new ApiActionResult("size:"+size);
}
【查看java對(duì)象所占的內(nèi)存大小的方法】相關(guān)文章:
電腦主板型號(hào)的查看方法07-19
java面向?qū)ο缶幊讨v解04-02
查看電腦最大內(nèi)存的方法03-23
java序列化對(duì)象的技巧03-27
java對(duì)象持久化的使用技巧03-28
JAVA對(duì)象創(chuàng)造及內(nèi)存布局介紹12-04
java顯示圖片的方法03-27
java的常見(jiàn)排序方法04-03
java文檔注釋的方法03-27