javapremain的简单介绍

博主:adminadmin 2022-12-04 07:39:06 81

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

本文目录一览:

怎么确定Java对象的大小

普通对象的结构如下,按64位机器的长度计算

1. 对象头(_mark), 8个字节

2. Oop指针,如果是32G内存以下的,默认开启对象指针压缩,4个字节

3. 数据区

4.Padding(内存对齐),按照8的倍数对齐

数组对象结构是

1. 对象头(_mark), 8个字节

2. Oop指针,如果是32G内存以下的,默认开启对象指针压缩,4个字节

3. 数组长度,4个字节

4. 数据区

5. Padding(内存对齐),按照8的倍数对齐

清楚了对象在内存的基本布局后,咱们说两种计算Java对象大小的方法

1. 通过java.lang.instrument.Instrumentation的getObjectSize(obj)直接获取对象的大小

2. 通过sun.misc.Unsafe对象的objectFieldOffset(field)等方法结合反射来计算对象的大小

java.lang.instrument.Instrumentation.getObjectSize()的方式

先讲讲java.lang.instrument.Instrumentation.getObjectSize()的方式,这种方法得到的是Shallow Size,即遇到引用时,只计算引用的长度,不计算所引用的对象的实际大小。如果要计算所引用对象的实际大小,可以通过递归的方式去计算。

java.lang.instrument.Instrumentation的实例必须通过指定javaagent的方式才能获得,具体的步骤如下:

1. 定义一个类,提供一个premain方法: public static void premain(String agentArgs, Instrumentation instP)

2. 创建META-INF/MANIFEST.MF文件,内容是指定PreMain的类是哪个: Premain-Class: sizeof.ObjectShallowSize

3. 把这个类打成jar,然后用java -javaagent XXXX.jar XXX.main的方式执行

有兴趣可以看下博主的:

如何查看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.lang.instrument能否被利用,对程序的执行进行干扰和破坏

java.lang.Instrument包是在JDK5引入的,程序员通过修改方法的字节码实现动态修改类代码。

这通常是在类的main方法调用之前进行预处理的操作,通过java指定该类的代理类来实现。

1. 代理 (agent) 是在你的main方法前的一个拦截器 (interceptor),也就是在main方法执行之前,执行agent的代码。

agent的代码与你的main方法在同一个JVM中运行,并被同一个system classloader装载,被同一的安全策略 (security policy) 和上下文 (context) 所管理。

叫代理(agent)这个名字有点误导的成分,它与我们一般理解的代理不大一样。java agent使用起来比较简单。

怎样写一个java agent? 只需要实现premain这个方法

public static void premain(String agentArgs, Instrumentation inst)

JDK 6 中如果找不到上面的这种premain的定义,还会尝试调用下面的这种premain定义:

public static void premain(String agentArgs)

2. Agent 类必须打成jar包,然后里面的 META-INF/MAINIFEST.MF 必须包含 Premain-Class这个属性。

下面是一个MANIFEST.MF的例子:

Manifest-Version: 1.0 Premain-Class:MyAgent1 Created-By:1.6.0_06

然后把MANIFEST.MF 加入到你的jar包中。

3. 所有的这些Agent的jar包,都会自动加入到程序的classpath中。所以不需要手动把他们添加到classpath。

除非你想指定classpath的顺序。

4. 一个java程序中-javaagent这个参数的个数是没有限制的,所以可以添加任意多个java agent。

所有的java agent会按照你定义的顺序执行。

例如:

java -javaagent:MyAgent1.jar -javaagent:MyAgent2.jar -jar MyProgram.jar

假设MyProgram.jar里面的main函数在MyProgram中。

MyAgent1.jar, MyAgent2.jar, 这2个jar包中实现了premain的类分别是MyAgent1, MyAgent2

程序执行的顺序将会是

MyAgent1.premain - MyAgent2.premain - MyProgram.main

5. 另外,放在main函数之后的premain是不会被执行的,

例如

java -javaagent:MyAgent1.jar -jar MyProgram.jar -javaagent:MyAgent2.jar

MyAgent2 和MyAgent3 都放在了MyProgram.jar后面,所以MyAgent2的premain都不会被执行,

所以执行的结果将是

MyAgent1.premain - MyProgram.main

6. 每一个java agent 都可以接收一个字符串类型的参数,也就是premain中的agentArgs,这个agentArgs是通过java option中定义的。

如:

java -javaagent:MyAgent2.jar=thisIsAgentArgs -jar MyProgram.jar

MyAgent2中premain接收到的agentArgs的值将是”thisIsAgentArgs” (不包括双引号)

7. 参数中的Instrumentation:

通过参数中的Instrumentation inst,添加自己定义的ClassFileTransformer,来改变class文件。

这里自定义的Transformer实现了transform方法,在该方法中提供了对实际要执行的类的字节码的修改,甚至可以达到执行另外的类方法的地步

8. 通过java agent就可以不用修改原有的java程序代码,通过agent的形式来修改或者增强程序了,或者做热启动等等。

关于javapremain和的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。

The End

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