檢視java物件所佔的記憶體大小的方法
做一些cache的時候,我們不可能把資料庫的所有的資料都快取到記憶體裡面,我們要估計快取的大小。那麼如何檢視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);
}
-
2017上半年計算機二級Java練習題及答案
計算機等級證書是我們找工作的敲門磚,現在越來越多人重視計算機等級考試。下面是本站小編為大家帶來的2017上半年計算機二級Java練習題及答案,希望對大家的學習有幫助!一、單選題1、結構化程式設計主要強調的是______。A、程式的規模B、程式的易讀性C、程式的執...
-
java的String=a; a==null和a.equals(null)這兩個判斷有什麼區別
1、String的==與equal()在對字串的相等判斷,==判斷的是地址是否相同,equal()判斷的是字元值是否相同。大多數時候==跟equal()的結果都是相同的。這是因為String物件是不變模式的,如果你不是明確地new一個String物件,Java對於String物件的儲存預設的是會把新生成...
-
Java基本元素詳解
生活呆以是甜的,也可以是苦的,但不能是沒味的。你可以勝利,也可以失敗,但你不能屈服,以下是小編為大家搜尋整理了Java基本元素詳解,希望能給大家帶來幫助!更多精彩內容請及時關注我們應屆畢業生考試網!第二章基本元素第一章總結:一平臺&JDK&JRE&JVM&A...
-
linux下執行java程式的sh指令碼教程
文章主要介紹了linux下執行java程式的sh指令碼,僅供參考,但是設定的時候環境變數是最重要的,我就是環境變數一直不對,總是按網上查到的來,不明白怎麼回事,才一直出錯,其實環境變數就是你要執行的java程式所在的位置。接下來是小編為大家收集的linux下執行java程式的sh腳...