JAVA堆外内存
本文建立在对instrumentation和agent有初步的了解的前提下阅读,关于这2个类的讲解在其它文章中。
这是一个maven项目,pom中需要的配置,lib中有asm的jar包
pom.xml文件:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>com.dxz</groupId>
<artifactId>chama</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging> <name>chama</name>
<url>http://maven.apache.org</url> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> <dependencies>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-test</artifactId>
<version>6.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-analysis</artifactId>
<version>6.2</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-commons</artifactId>
<version>6.2</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-tree</artifactId>
<version>6.2</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-util</artifactId>
<version>6.2</version>
</dependency>
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.12.1.GA</version>
</dependency> <!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.5</version>
</dependency> <!-- https://mvnrepository.com/artifact/oro/oro -->
<dependency>
<groupId>oro</groupId>
<artifactId>oro</artifactId>
<version>2.0.8</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>utf-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<!-- <Premain-Class>com.dxz.chama.javaagent.patter.TimeMonitorPatterAgent</Premain-Class> -->
<!-- <Premain-Class>com.dxz.chama.javaagent.StatAgent</Premain-Class> -->
<Premain-Class>com.dxz.chama.javaagent.asm.UdAgent</Premain-Class>
</manifestEntries>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
打包后的agent的jar包中manifest属性如下:
agent类,只有一个方法,就是把自定义的类修改器添加到instrumentation中。
package com.dxz.chama.javaagent.asm; import java.lang.instrument.Instrumentation; public class UdAgent {
public static void premain(String agentArgs, Instrumentation instrumentation){
instrumentation.addTransformer(new LogTransformer());
}
}
类转换器实现:
package com.dxz.chama.javaagent.asm; import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain; import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter; public class LogTransformer implements ClassFileTransformer {
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
try {
ClassReader cr = new ClassReader(className);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
TimeCountAdpter timeCountAdpter = new TimeCountAdpter(cw); cr.accept(timeCountAdpter, ClassReader.EXPAND_FRAMES); return cw.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
实际修改字节码的方法,这里给每个类添加了一个字段UDASMCN,用于记录当前类的名字(方便打印信息)。同时记录每个方法的名字,以及执行时间。
package com.dxz.chama.javaagent.asm; import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.AnalyzerAdapter;
import org.objectweb.asm.commons.LocalVariablesSorter; public class TimeCountAdpter extends ClassVisitor implements Opcodes {
private String owner;
private boolean isInterface;
private String filedName = "UDASMCN";
private int acc = Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL;
private boolean isPresent = false; private String methodName; public TimeCountAdpter(ClassVisitor classVisitor) {
super(ASM6, classVisitor);
} @Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
super.visit(version, access, name, signature, superName, interfaces);
owner = name;
isInterface = (access & ACC_INTERFACE) != 0;
} @Override
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
if (name.equals(filedName)) {
isPresent = true;
}
return super.visitField(access, name, descriptor, signature, value);
} @Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature,
String[] exceptions) {
MethodVisitor mv = cv.visitMethod(access, name, descriptor, signature, exceptions); if (!isInterface && mv != null && !name.equals("<init>") && !name.equals("<clinit>")) {
methodName = name;
AddTimerMethodAdapter at = new AddTimerMethodAdapter(mv);
at.aa = new AnalyzerAdapter(owner, access, name, descriptor, at);
at.lvs = new LocalVariablesSorter(access, descriptor, at.aa); return at.lvs;
} return mv;
} public void visitEnd() {
if (!isInterface) {
FieldVisitor fv = cv.visitField(acc, filedName, "Ljava/lang/String;", null, owner);
if (fv != null) {
fv.visitEnd();
}
}
cv.visitEnd();
} class AddTimerMethodAdapter extends MethodVisitor {
private int time;
private int maxStack;
public LocalVariablesSorter lvs;
public AnalyzerAdapter aa; public AddTimerMethodAdapter(MethodVisitor methodVisitor) {
super(ASM6, methodVisitor);
} @Override
public void visitCode() {
mv.visitCode();
mv.visitMethodInsn(INVOKESTATIC, "java/lang/System", "nanoTime", "()J", false);
time = lvs.newLocal(Type.LONG_TYPE);
mv.visitVarInsn(LSTORE, time);
maxStack = 4;
} @Override
public void visitInsn(int opcode) {
if (((opcode >= IRETURN && opcode <= RETURN) || opcode == ATHROW) && !isPresent) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/System", "nanoTime", "()J", false);
mv.visitVarInsn(LLOAD, time);
mv.visitInsn(LSUB);
mv.visitVarInsn(LSTORE, time); mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); mv.visitTypeInsn(NEW, "java/lang/StringBuilder");
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V", false);
mv.visitFieldInsn(GETSTATIC, owner, filedName, "Ljava/lang/String;");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append",
"(Ljava/lang/String;)Ljava/lang/StringBuilder;", false); mv.visitLdcInsn(" " + methodName + ":");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append",
"(Ljava/lang/String;)Ljava/lang/StringBuilder;", false); mv.visitVarInsn(LLOAD, time);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(J)Ljava/lang/StringBuilder;",
false);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); maxStack = Math.max(aa.stack.size() + 4, maxStack);
}
mv.visitInsn(opcode);
} @Override
public void visitMaxs(int maxStack, int maxLocals) {
super.visitMaxs(Math.max(maxStack, this.maxStack), maxLocals);
}
} }
打包成jar包后,在另一个程序启动时调用,启动参数如下:
-javaagent:D:\study\chama\target\chama-0.0.1-SNAPSHOT.jar
执行效果:
时间单位是纳秒,可以看到每个方法执行完时,都会打印这个方法 的执行时间,以com/Main main:11457636为例,说明类com/Main的main方法执行力11毫秒。
JAVA堆外内存的更多相关文章
- google-perftools 分析JAVA 堆外内存
google-perftools 分析JAVA 堆外内存 分类: j2se2011-08-25 21:48 3358人阅读 评论(4) 收藏 举报 javahbasehtml工具os 原文转自:htt ...
- Java堆外内存管理
Java堆外内存管理 1.JVM可以使用的内存分外2种:堆内存和堆外内存: 堆内存完全由JVM负责分配和释放,如果程序没有缺陷代码导致内存泄露,那么就不会遇到java.lang.OutOfMemo ...
- Java堆外内存之二:堆外内存使用总结
目录: <堆外内存操作类ByteBuffer> <DirectBuffer> <Unsafe(java可直接操作内存(),挂起与恢复,CAS操作)> 有时候对内存进 ...
- 实战经验 | Cassandra Java堆外内存排查经历全记录
背景 最近准备上线cassandra这个产品,同事在做一些小规格ECS(8G)的压测.压测时候比较容易触发OOM Killer,把cassandra进程干掉.问题是8G这个规格我配置的heap(Xmx ...
- 超干货!Cassandra Java堆外内存排查经历全记录
背景 最近准备上线cassandra这个产品,同事在做一些小规格ECS(8G)的压测.压测时候比较容易触发OOM Killer,把cassandra进程干掉.问题是8G这个规格我配置的heap(Xmx ...
- Java堆外内存的使用
堆外内存的回收见HeapByteBuffer和DirectByteBuffer以及回收DirectByteBuffer 基本类型长度 在Java中有很多的基本类型,比如: byte,一个字节是8位bi ...
- Netty之Java堆外内存扫盲贴
Java的堆外内存本来是高贵而神秘的东西,只在一些缓存方案的收费企业版里出现.但自从用了Netty,就变成了天天打交道的事情,毕竟堆外内存能减少IO时的内存复制,不需要堆内存Buffer拷贝一份到直接 ...
- Java 堆外内存
入口ByteBuffer.allocateDirect public static ByteBuffer allocateDirect(int capacity) { return new Direc ...
- Java堆外内存之突破JVM枷锁
对于有Java开发经验的朋友都知道,Java中不需要手动的申请和释放内存,JVM会自动进行垃圾回收:而使用的内存是由JVM控制的. 那么,什么时机会进行垃圾回收,如何避免过度频繁的垃圾回收?如果JVM ...
- Java堆外内存之五:堆外内存管理类ByteBuffer
本篇主要讲解如何使用直接内存(堆外内存),并按照下面的步骤进行说明: 相关背景-->读写操作-->关键属性-->读写实践-->扩展-->参考说明 希望对想使用直接内存的朋 ...
随机推荐
- EventSource
<!doctype html> <html> <head> <meta charset="UTF-8"> <title> ...
- 实现手机扫描二维码页面登录,类似web微信-第三篇,手机客户端
转自:http://www.cnblogs.com/fengyun99/p/3541254.html 上一篇,介绍了二维码生成的机制,紧接着,我们就要开发手机客户端来识别这个二维码. 二维码,实际上是 ...
- input标签实现让光标不出现!
实现不让光标出现的效果,很好用,例子如下: <input class="red" readonly unselectable="on" value=&qu ...
- asp.net导出word(word2007)
1.只能导出成word2007格式(.docx),可直接导出到客户端 2.服务器上不需要装任何东西,也没有权限限制,比较适合导出表格(支持图片) 3.需要一个国外的DocX.dll插件 4.需要添加引 ...
- Allegro建立引脚封装概念名词梳理
首先感谢于博士的60讲的Cadence教学视频,老师讲的还是很有耐心,很细致,谢谢! 目前还只是看到建立PCB封装这一块,正好手头上有个案子在做,边做边学的进度还是要好很多.以前的工作对原理图这一块的 ...
- Modules
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...
- AngularJS从构建项目开始
AngularJS从构建项目开始 AngularJS体验式编程系列文章,将介绍如何用angularjs构建一个强大的web前端系统.angularjs是由Google团队开发的一款非常优秀web前端框 ...
- Angularjs中的promise
promise 是一种用异步方式处理值的方法,promise是对象,代表了一个函数最终可能的返回值或抛出的异常.在与远程对象打交道非常有用,可以把它们看成一个远程对象的代理. 要在Angular中创建 ...
- C++ Primer : 第十三章 : 拷贝控制之对象移动
右值引用 所谓的右值引用就是必须将引用绑定到右值的引用,我们通过&&来绑定到右值而不是&, 右值引用只能绑定到即将销毁的对象.右值引用也是引用,因此右值引用也只不过是对象的别名 ...
- mysql添加外键
语法:alter table 表名 add constraint FK_ID foreign key(你的外键字段名) REFERENCES 外表表名(对应的表的主键字段名); 例: alter ta ...