糯米文學吧

位置:首頁 > 計算機 > java語言

查看java對象所佔的內存大小的方法

java語言3.01W

做一些cache的時候,我們不可能把數據庫的所有的數據都緩存到內存裏面,我們要估計緩存的大小。那麼如何查看java對象所佔的內存大小呢?本文為大家介紹一下方法,希望可以為您提供幫助!更多內容請關注應屆畢業生考試網!

查看java對象所佔的內存大小的方法

(1)做一些cache的時候,我們不可能把數據庫的所有的數據都緩存到內存裏面,我們要估計緩存的大小。

(2)內存泄露的時候,我們可以查看某些對象的大小來定位問題,當然還有其他的更有效的方式,比如使用MAT分析dump文件

(3)根據jvm的堆內存設置,我們可以知道最多可以創建多少個對象。

從jdk5開始,提供了Instrumentation API,它有一個叫做getObjectSize()的方法,但是,這個方法存在兩個問題:

(1)不可以直接使用。必須要實現一個Instrumentation Agent,還得放到jar包裏面。

(2)它只能返回單個對象的大小,不能返回內部包含的.子對象的大小。

關於第一個問題,很好解決,在任何一個類裏面聲明一個"premain"方法,就可以把這個類做成是一個agent:

public class SizeOfAgent {

static Instrumentation inst;

/** initiALizes agent */

public static void premain(String agentArgs, Instrumentation instP) {

inst = instP;

}

}

jvm在啟動的時候會調用premain()方法,同時會傳遞Instrumentation這個對象實例,要告訴jvm Instrumentation agent所在的類,需要把這個類打到jar包裏面,

然後在這個文件設置一些屬性:

Premain-Class: OfAgent

Boot-Class-Path:

Can-Redefine-Classes: false

java應用在啟動的時候,指定-javaagent參數:

java -javaagent: <Your main class>

拿到Instrumentation這個實例以後,就可以調用sizeOf()方法了:

public class SizeOfAgent {

static Instrumentation inst;

// ...

public static long sizeOf(Object o) {

return bjectSize(o);

}

}

然後可以使用反射來獲取子對象的大小。

  完整的代碼如下:

package ;

import rumentation;

import y;

import d;

import fier;

import tityHashMap;

import ;

import k;

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 bjectSize(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 (!pty()) {

result += internalSizeOf((), stack, visited);

}

r();

return result;

}

private static boolean skipObject(Object obj, Map<Object, Object> visited) {

if (obj instanceof String) {

// skip interned string

if (obj == ((String) obj)rn()) {

return true;

}

}

return (obj == null) // skip visited object

|| ainsKey(obj);

}

private static long internalSizeOf(Object obj, Stack<Object> stack,

Map<Object, Object> visited) {

if (skipObject(obj, visited)) {

return 0;

}

(obj, null);

long result = 0;

// get size of object + primitive variables + member pointers

result += Of(obj);

// process all array elements

Class clazz = lass();

if (ray()) {

if (ame()th() != 2) {// skip primitive type array

int length = ength(obj);

for (int i = 0; i < length; i++) {

((obj, i));

}

}

return result;

}

// process all fields of the object

while (clazz != null) {

Field[] fields = eclaredFields();

for (int i = 0; i < th; i++) {

if (!atic(fields[i]odifiers())) {

if (fields[i]ype()imitive()) {

continue; // skip primitive fields

} else {

fields[i]ccessible(true);

try {

// objects to be estimated are put to stack

Object objectToAdd = fields[i](obj);

if (objectToAdd != null) {

(objectToAdd);

}

} catch (IllegalAccessException ex) {

assert false;

}

}

}

}

clazz = uperclass();

}

return result;

}

}

  然後我們可以做一個測試:

public class Test {

static class Person{

private int id;

private String name;

private String address;

public Person(int id, String name, String address) {

= id;

= name;

ess = address;

}

}

public static void main(String[] args) throws Exception {

Person p = new Person(12, "xujsh","bj");

long size = SizeOf(p);

tln(size);

}

}

切換到命令行:

D:workspaceobjsizesrc>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:workspaceobjsizesrc>javac com/bj58/test/*

D:workspaceobjsizesrc>jar -cvfm com/bj58/test/*

標明清單(manifest)

增加:com/bj58/test/s(讀入= 3119) (寫出= 1698)(壓縮了 45%)

增加:com/bj58/test/(讀入= 3147) (寫出= 1204)(壓縮了 61%)

增加:com/bj58/test/Test$s(讀入= 442) (寫出= 305)(壓縮了 30%)

增加:com/bj58/test/s(讀入= 692) (寫出= 441)(壓縮了 36%)

增加:com/bj58/test/(讀入= 509) (寫出= 290)(壓縮了 43%)

D:workspaceobjsizesrc>java -javaagent:

24

Manifest-Version: 1.0

Main-Class:

Premain-Class: OfAgent

Boot-Class-Path:

Can-Redefine-Classes: false

【注意】文件的格式要求比較嚴格,每一行要滿足:key:空格value回車

如何在web應用程序裏面使用呢?

以我的tomcat為例,

(1)把上傳tomcat的lib目錄下面

(2)修改:

添加一行:

JAVA_OPTS="$JAVA_OPTS -javaagent:$CATALINA_HOME/lib/" //這一行是新添加的

if [ -z "$LOGGING_MANAGER" ]; then

JAVA_OPTS="$JAVA_OPTS ger=sLoaderLogManager"

else

JAVA_OPTS="$JAVA_OPTS $LOGGING_MANAGER"

fi

(3)在應用裏面添加一個controler:

@Path(value = "/api/size")

@GET

public ActionResult size() {

Map<Long, List<Long>> map = otindexBaidu();

long size = SizeOf(map);

return new ApiActionResult("size:"+size);

}