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
本篇主要讲解如何使用直接内存(堆外内存),并按照下面的步骤进行说明: 相关背景-->读写操作-->关键属性-->读写实践-->扩展-->参考说明 希望对想使用直接内存的朋 ...
随机推荐
- investopedia level 2
Mispricing can be explained by the sum of the two components: true mispricing and estimation errorVe ...
- VaildForm 自定义提示消息
ValidForm插件提供了7种提示效果,其中有四种自定义效果,具体访问地址:http://validform.rjboy.cn/demo.html 个人偏爱其中两种,即 l 提示效果四:[自定义提示 ...
- String课后作业
请查看String.equals()方法的实现代码,注意学习其实现方法. public class StringEquals { @param args the command line argume ...
- ES6 基础版迭代器
ES6中引入了generator function* get() { var result1 = yield c; var result2 = yield b; var result3 = yield ...
- DAO JDBC 学生成绩管理系统
1:student.course类 package JDBCU; public class Student { private String no; private String name; publ ...
- (DFS)codevs1004-四子连棋
题目地址 方法是建立dfs,并在其中加入pre变量,记录之前移动的是W还是B.外面套for循环,从1步开始逐次递增,直到在i步时可以走完(dfs返回1),break退出循环,即为最短步. 本题的关键主 ...
- DTO概念
在开发过程中用到了DTO,简单了解了一下. DTO:数据传输对象,用来连接表现层和应用层之间的数据交互.数据传输对象是没有行为的POJO对象,它的目的只是为了对领域对象进行数据封装,实现层与层之间的数 ...
- Struts1的核心对象
1.ActionServlet.ActionMapping.ActionForm.ActionForward 2.config = "/WEB-INF/struts-config.xml&q ...
- Activity启动清空原任务栈
就是 启动新的activity 但是把之前所有的activity 都finish掉 而且所有的activity 都是在一个栈中 Intent intent = new Intent();intent ...
- SQL Server基本函数
1. 字符串函数 1.1 datalength( char_expr ) ,返回表达式的字节数,不包含尾随空格 返回类型:如果 expression 的数据类型为 varchar(max).nvarc ...