「java对象内存统计」java计算对象的内存大小

博主:adminadmin 2022-11-27 17:13:08 120

今天给各位分享java对象内存统计的知识,其中也会对java计算对象的内存大小进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

本文目录一览:

如何计算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怎么测试一个对象所占的内存的大小?

这是一个测试的方法,参考网上的,具体可以看提供给你的网址

package com;

public class Sizeof {

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

// Warm up all classes/methods we will use

runGC();

usedMemory();

// Array to keep strong references to allocated objects

final int count = 100000;

Object[] objects = new Object[count];

long heap1 = 0;

// Allocate count+1 objects, discard the first one

for (int i = -1; i count; ++i) {

Object object = null;

// Instantiate your data here and assign it to object

object = new Object();

// object = new Integer (i);

// object = new Long (i);

// object = new String ();

// object = new byte [128][1]

if (i = 0)

objects[i] = object;

else {

object = null; // Discard the warm up object

runGC();

heap1 = usedMemory(); // Take a before heap snapshot

}

}

runGC();

long heap2 = usedMemory(); // Take an after heap snapshot:

final int size = Math.round(((float) (heap2 - heap1)) / count);

System.out.println("'before' heap: " + heap1 + ", 'after' heap: "

+ heap2);

System.out.println("heap delta: " + (heap2 - heap1) + ", {"

+ objects[0].getClass() + "} size = " + size + " bytes");

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

objects[i] = null;

objects = null;

}

private static void runGC() throws Exception {

// It helps to call Runtime.gc()

// using several method calls:

for (int r = 0; r 4; ++r)

_runGC();

}

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

}

}

private static long usedMemory() {

return s_runtime.totalMemory() - s_runtime.freeMemory();

}

private static final Runtime s_runtime = Runtime.getRuntime();

}

如何查看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对象到底占多大内存

第一问中,integer,Double是可以准确知道大小的

java中int double(包装类分别是Integer和Double,实际是一样的)分别占用的大小是4B 和8B

这里说的B,就是我们通常说的KB中的那个B,全称是Byte。

1B = 8bit。 所以我们通常会说int是32位,有时候又4字节

而String他是有char数组组成,一个长度为10的String,占用的char就是10个,一个char是2B。

所以看String占多少内存,需要知道String的长度

二问中:答案是可以的

摘自ObjectOutPutStream的API说明

FileOutputStream fos = new FileOutputStream("t.tmp");

ObjectOutputStream oos = new ObjectOutputStream(fos);

oos.writeInt(12345);

oos.writeObject("Today");

oos.writeObject(new Date());

oos.close();

查看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对象占用的内存

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计算对象的内存大小的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。

The End

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