「计算java对象所占内存」计算java对象所占内存数量

博主:adminadmin 2022-12-22 22:36:07 61

本篇文章给大家谈谈计算java对象所占内存,以及计算java对象所占内存数量对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。

本文目录一览:

如何计算一个对象占用的内存空间

Java没有提供现成的函数去计算对象的内存空间,不过可以用大量产生某个对象然后计算平均值的方法近似获得该对象占用的内存。

写个例子给你:

public class Test{

long f1 = Runtime.getRuntime().freeMemory();

for(int i=0;i1000;i++)

{

MyObject t = new MyObject();

}

long f2 = Runtime.getRuntime().freeMemory();

System.out.println((f1-f2)/1000);//输出每个对象占用的字节数

}

}

如何计算java对象占用的内存

Java有一个很好的地方就是java的垃圾收集机制,这个机制集成于jvm的,对程序员来说是隐藏且不透明的。这种情况下,如何得到某个对象消耗的内存呢?

曾经看到过有人用以下方法来计算:在生成该object的前后都调用java.lang.Runtime.freeMemory()方法,然后看两者之差即为该object消耗的内存量。

这种方法的代码是:

long totalMem = java.lang.Runtime.freeMemory();

Object myBigObject = null;

System.out.println("You just got rid of " + totalMem

- java.lang.Runtime.freeMemory());

这种想法是对的,但是实际上,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的源代码:

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" );

}

}

实际上,这种方法基本上正确了,但是By Tony Sintes疏忽了一点,就是仅仅Runtime.getRuntime().gc();并不能真正完成垃圾收集,也就是说实际上jvm的内存此时并不是稳定的。

所以,只有当内存不再发生大的变动,或者说已经稳定,我们才可能说垃圾收集已经完成。

如何才能真正确保基本完成了jvm的垃圾收集呢?实现这个功能的代码如下:

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 ();

}

}

如何计算Java对象所占内存的大小

java中可以用.getBytes().length获取字符串占用内容的大小,原理是java中任何字符都采用Unicode编码,所以衡量占用内存大小采用占用的字节数。

举例如下:

public

class

TestStringSize

{

public

static

final

void

main(String[]

args)

{

System.out.println("占用内存大小:"+"学java".getBytes().length);

}

}

输出结果:

占用内存大小:6

byte

查看java对象占堆内存多少个字节

object

o=new

object():

在java中空对象占八个字节,对象的引用占四个字节。所以上面那条语句所占的空间是4byte+8byte=12byte.java中的内存是以8的倍数来分配的,所以分配的内存是16byte.

举个例子:

class

o{

int

i;

byte

j;

string

s;

}

其所占内存的大小是空对象(8)+int(4)+byte(1)+string引用(4)=17byte,因要是8的整数倍,所以其占大小为24byte.

当然,如果类里有其他对象的话,也要把其他对象的空间算进去。

如何查看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包里面,

然后在manifest.mf这个文件设置一些属性:

Premain-Class: sizeof.agent.SizeOfAgent

Boot-Class-Path:

Can-Redefine-Classes: false

java应用在启动的时候,指定-javaagent参数:

java -javaagent:sizeofag.jar Your main class

拿到Instrumentation这个实例以后,就可以调用sizeOf()方法了:

public class SizeOfAgent {

static Instrumentation inst;

// ...

public static long sizeOf(Object o) {

return inst.getObjectSize(o);

}

}

然后可以使用反射来获取子对象的大小。

完整的代码如下:

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) {

MapObject, Object visited = new IdentityHashMapObject, Object();

StackObject stack = new StackObject();

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, MapObject, 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, StackObject stack,

MapObject, 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;

}

}

然后我们可以做一个测试:

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\srcjava -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\srcjavac com/bj58/test/*.java

D:\workspace\objsize\srcjar -cvfm size.jar MANIFEST.MF com/bj58/test/*

标明清单(manifest)

增加:com/bj58/test/SizeOfAgent.class(读入= 3119) (写出= 1698)(压缩了 45%)

增加:com/bj58/test/SizeOfAgent.java(读入= 3147) (写出= 1204)(压缩了 61%)

增加:com/bj58/test/Test$Person.class(读入= 442) (写出= 305)(压缩了 30%)

增加:com/bj58/test/Test.class(读入= 692) (写出= 441)(压缩了 36%)

增加:com/bj58/test/Test.java(读入= 509) (写出= 290)(压缩了 43%)

D:\workspace\objsize\srcjava -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文件的格式要求比较严格,每一行要满足:key:空格value回车

如何在web应用程序里面使用呢?

以我的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)在应用里面添加一个controler:

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

@GET

public ActionResult size() {

MapLong, ListLong map = ApiUtils.getHotindexBaidu();

long size = SizeOfAgent.fullSizeOf(map);

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

}

然后就可以用浏览器来访问了。

关于计算java对象所占内存和计算java对象所占内存数量的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。

The End

发布于:2022-12-22,除非注明,否则均为首码项目网原创文章,转载请注明出处。