jvm原理

JVM源码分析之javaagent原理完全解读

我只是一个虾纸丫 提交于 2020-04-05 20:58:09
概述 本文重点讲述javaagent的具体实现,因为它面向的是我们Java程序员,而且agent都是用Java编写的,不需要太多的C/C++编程基础,不过这篇文章里也会讲到JVMTIAgent(C实现的),因为javaagent的运行还是依赖于一个特殊的JVMTIAgent。 对于javaagent,或许大家都听过,甚至使用过,常见的用法大致如下: java -javaagent:myagent.jar=mode=test Test 我们通过-javaagent来指定我们编写的agent的jar路径(./myagent.jar),以及要传给agent的参数(mode=test),在启动的时候这个agent就可以做一些我们希望的事了。 javaagent的主要功能如下: 可以在加载class文件之前做拦截,对字节码做修改 可以在运行期对已加载类的字节码做变更,但是这种情况下会有很多的限制,后面会详细说 还有其他一些小众的功能 获取所有已经加载过的类 获取所有已经初始化过的类(执行过clinit方法,是上面的一个子集) 获取某个对象的大小 将某个jar加入到bootstrap classpath里作为高优先级被bootstrapClassloader加载 将某个jar加入到classpath里供AppClassloard去加载 设置某些native方法的前缀

JVM源码分析之javaagent原理完全解读

帅比萌擦擦* 提交于 2020-03-24 12:22:05
问题描述 当我们一个系统既需要mysql驱动,也需要oracle驱动的时候,在并发加载初始化这些驱动类的过程中产生死锁的可能性非常大,下面是一个模拟的例子,对于Thread2的实现其实是jdk里java.sql.DriverService的逻辑,也是我们第一次调用java.sql.DriverManager.registerDriver注册一个驱动实例要走的逻辑(jdk1.6下),不过这篇文章是使用我们生产环境的一个系统的线程dump和内存dump为基础进行分析展开的。 如果以上代码运行过程中发现有线程一直卡死在Class.forName的调用里,那么说明问题已经重现了。 先上两张图 内存态线程堆栈 线程堆栈 存疑点 仔细看看上面的线程dump分析和内存dump分析里的线程分析模块,您可能会有如下两个疑惑: 【为什么线程[Thread-0]一直卡在Class.forName的位置】:这有点出乎意料,做一个类加载要么找不到抛出ClassNotFoundException,要么找到直接返回,为什么会一直卡在这个位置呢? 【明明[Thread-0]注册的是mysql驱动为什么会去加载Odbc的驱动类】:通过[Thread-0]在栈上看倒数第二帧展开看到传入Class.forName的参数是com.mysql.jdbc.Driver,然后展开栈上顺序第二帧,看到传入的参数是sun.jdbc

JVM的动态技术初始(一)热更新

帅比萌擦擦* 提交于 2020-03-17 22:56:35
1.热更新的概念 热更新就是动态下发代码,它可以使开发者在不发布新版本的情况下,修复 BUG 和发布功能。 一般这样的概念我会去整理它的输入什么,输出什么,来快速将抽象具体化。 热更新的输入是:代码的字节码文件 输出是:运行的结果是走新修改的文件逻辑得出来的 2.使用工具 使用的工具是阿里的Arthas和JDK自带的Java VisualVM 3.操作过程 在服务一直运行的状态下,在线修改一下线上代码,来让第二次同样的请求得到不一样的逻辑结果。 下面开始我的热更新初体验: 1.安装和启动Arthas 安装和启动大家可以去看文章底部 引用 里面的 Arthas的用户手册 比我说的简单清晰,还可以在线运行。 提一句,运行Arthas需要启动的服务的pid: liunx中使用 ps -ef 命令 对应行的第二个参数就是pid, windows中可以使用jdk自带的虚拟机监控查看,直接win键+R键 然后输入 jvisualvm 回车就会出现下图中的,很好辨别 2. 反编译线上的类文件 Arthas中的jad命令( jad 类路径.类名 )可以直接在线反编译出线上运行的代码(可用于查看自己线上运行的代码是不是最新代码) 也可以使用 jad 类路径.类名 > 要保存的路径+文件名 jad - -source -only com.saicmobility.cms.gtw.controller

JVM--一文读懂垃圾回收

最后都变了- 提交于 2020-03-16 21:50:00
JVM--一文读懂垃圾回收 与其他语言相比,例如c/c++,我们都知道,java虚拟机对于程序中产生的垃圾,虚拟机是会自动帮我们进行清除管理的,而像c/c++这些语言平台则需要程序员自己手动对内存进行释放。 虽然这种自动帮我们回收垃圾的策略少了一定的灵活性,但却让代码编写者省去了很多工作,同时也提高了很多安全性。(因为像C/C++假如你创建了大量的对象,但却由于自己的疏忽忘了将他们进行释放,可能会造成内存溢出)。 何为垃圾? 刚才说了,虚拟机会自动帮助我们进行垃圾的清除,那什么样的对象我们才可以称为是垃圾对象呢? 假如你创建了一个对象 Man m = new Man(); 你用一个变量指向了这个对象,显然对于这个对象,你可以用变量m对这个对象进行利用,但过了一段时间,你执行了 m = null; 并且也并没有新的变量来指向刚才创建的对象。此时对于这个没有任何变量指向的对象,你觉得它还有用处吗? 显然,对于这种没有被变量指向的对象,它是一点卵用也没有的,它只能在 堆 随风漂流。 因此,对于这样的对象,我们就可以把它称为垃圾了,它早晚会被垃圾回收器给干掉。 怎么知道它已经是垃圾对象了? 假如代码是你自己编写的,你可能知道这个对象啥时候应该被抛弃,你可以随时让它成为垃圾对象。 但是,你毕竟是你,虚拟机则没那么智能。那虚拟机是如何知道的呢? 上面已经说了,没有变量引用这个对象时

JVM系列八(虚拟机性能监控命令).

醉酒当歌 提交于 2020-03-15 23:26:33
jps JVM Process Status Tool,显示指定系统内所有的 HotSpot 虚拟机进程。显示信息包括虚拟机执行主类名称以及这些进程的本地虚拟机唯一ID(Local Virtual Machine Identifier,LVMID)。 jps [-q] [-mlvV] [<hostid>] 选项 作用 -q 只输出 LVMID,省略主类的名称 -m 输出虚拟机进程启动时传递给主类 main() 函数的参数 -l 输出主类的名称,如果进程执行的是 jar 包,输出 jar 路径 -v 输出虚拟机进程启动时 JVM 参数 jstat JVM Statistics Monitoring Tool,用于收集 HotSpot 虚拟机各方面的运行数据。包括显示本地或者远程虚拟机进程中的类装载、内存、垃圾收集、JIT 编码等运行数据。 jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]] 参数 interval 和 count 代表查询间隔和次数,如果省略这两个参数,说明只查询一次。 选项 作用 -class 监视类装载、卸载数量、总空间以及类装载所耗费的时间 -compiler 输出 JIT 编译过的方法、耗时等信息 -printcompilation 输出已经被 JIT 编译的方法 -gc 监视 Java

Tomcat8优化--JVM字节码

我是研究僧i 提交于 2020-03-10 19:52:50
JVM字节码   前面我们通过tomcat本身的参数以及jvm的参数对tomcat做了优化,其实要想将应用程 序跑的更快、效率更高,除了对tomcat容器以及jvm优化外,应用程序代码本身如果写 的效率不高的,那么也是不行的,所以,对于程序本身的优化也就很重要了。   对于程序本身的优化,可以借鉴很多前辈们的经验,但是有些时候,在从源码角度方面 分析的话,不好鉴别出哪个效率高,如对字符串拼接的操作,是直接“+”号拼接效率高还 是使用StringBuilder效率高?   这个时候,就需要通过查看编译好的class文件中字节码,就可以找到答案。   我们都知道,java编写应用,需要先通过javac命令编译成class文件,再通过jvm执行, jvm执行时是需要将class文件中的字节码载入到jvm进行运行的。 1、通过javap命令查看class文件的字节码内容 1.1 创建一个简单的测试类 public class Test1 { public static void main(String[] args) { int a = 2; int b = 5; int c = b-a; System.out.println(c); } } 执行成功target目录下便会生成class文件:    1.2 cmd 使用命令 javap -v Test1.class > Test1.txt

JVM运行时数据区域

三世轮回 提交于 2020-03-09 05:17:22
一、运行时数据区域 相应脑图 程序计数器 记录正在执行的虚拟机字节码指令的地址(如果正在执行的是本地方法则为空)。 Java 虚拟机栈 每个 Java 方法在执行的同时会创建一个 栈帧 用于 存储局部变量表 、 操作数栈 、 常量池引用等信息 。 从方法调用直至执行完成的过程,就对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程。 对于执行引擎来说,活动线程中,只有栈顶的栈帧是有效的,称为 当前栈帧 ,这个栈帧所关联的方法称为 当前方法 。 执行引擎所运行的所有字节码指令都只针对当前栈帧进行操作。 操作数栈: 一个后进先出(Last-In-First-Out)的操作数栈,也可以称之为表达式栈(Expression Stack)。 操作数栈和局部变量表在访问方式上存在着较大差异,操作数栈并非采用访问索引的方式来进行数据访问的, 而是**通过标准的入栈和出栈操作来完成一次数据访问**。 每一个操作数栈都会拥有一个明确的栈深度用于存储数值,一个32bit的数值可以用一个单位的栈深度来存储,而2个单位的栈深度则可以保存一个64bit的数值, 当然操作数栈所需的容量大小在编译期就可以被完全确定下来,并保存在方法的Code属性中。 可以通过 -Xss 这个虚拟机参数来指定每个线程的 Java 虚拟机栈内存大小: java -Xss512M HackTheJava 该区域可能抛出以下异常:

面试题之JVM内存区域

余生颓废 提交于 2020-03-09 05:15:40
1、Java内存区域(运行时数据区域):   jdk1.8之前:虚拟机运行内存分栈、堆和方法区这几种。 栈:虚拟机栈、本地方法栈、程序计数器。(线程私有,每个线程都拥有各自的) 程序计数器:一块比较小的内存空间,可以看做是当前线程所执行的字节码的行号指示器。主要有2个作用: 字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理。 在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪里了。 注意:唯一一个不会出现OutOfMemoryError的内存区域,它的生命周期随着线程的创建而创建,随着线程的结束而死亡。 Java虚拟机栈:生命周期与线程相同(随着线程创建而创建,随着线程死亡而死亡),描述的是Java方法执行的内存模型,每次方法调用的数据都是通过栈传递的。Java内存大概就是堆内存和栈内存,栈是虚拟机栈或是虚拟机栈中局部变量表部分。(实际上,Java虚拟机栈是由一个个栈帧组成,每个栈帧中都拥有:局部变量表、操作数、动态链接、方法出口信息) 局部变量表主要存放了编译器可知的各种数据类型 (boolean、byte、char、short、int、float、long、double)、 对象引用 (reference类型,不同于对象本身,可能是指向一个代表对象起始地址的引用指针

《面试必问之jvm与性能优化》(二)

烂漫一生 提交于 2020-03-07 17:16:12
1. 说说各个区域的作用? 1、运行时数据区域 运行时数据区域包括方法区、虚拟机栈、本地方法栈、堆、程序计数器。其中方法区和堆是所有线程共享的数据区,其他的是线程隔离的数据区。 1.1、程序计数器 程序计数器是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的行号指示器,确定下一条需要执行的字节码指令。java的多线程是通 过线程轮流切换并分配处理器执行时间的方式来实现的,在任何确定的一个时刻,一个处理器只会执行一条线程中的指令。为了线程切换之后能恢复到正确的执行位 置,每个线程都需要有一个独立的程序计数器,各个线程之间的计数器互不影响。如果线程正在执行的是一个java方法,则计数器记录的是正在执行的虚拟机字 节码指令的地址,如果正在执行的是native方法,则计数器值为空。 1.2、java虚拟机栈 java虚拟机栈也是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是java方法执行的内存模型:每个方法被执行的时候都会创建一个栈帧用 于存在局部变量表、操作栈、动态链接、方法出口等信息。通过所说的栈是局部变量表,即与对象内存分配关系最密切的内存区域。局部变量表的内存空间在编译期 间完成分配,当进入一个方法时,这个方法需要在帧中分配多大的局部变量空间是确定的,在运行期不会改变。 java虚拟机栈有两种异常:如果线程请求的栈深度大于虚拟机所允许的深度

京东资深架构带你深入理解JVM高级特性+最佳实践

允我心安 提交于 2020-03-06 17:25:56
本人免费整理了Java高级资料,涵盖了Java、Redis、MongoDB、MySQL、Zookeeper、Spring Cloud、Dubbo高并发分布式等教程,一共30G,需要自己领取。 传送门: https://mp.weixin.qq.com/s/osB-BOl6W-ZLTSttTkqMPQ 前言 Java是目前用户最多、使用范围最广的软件开发技术之一。Java 的技术体系主要由支撑Java程序运行的虚拟机、提供各开发领域接口支持的Java API、Java 编程语言及许多第三方Java框架(如Spring.Struts等)构成。在国内,有关JavaAPI、Java语言语法及第三方框架的技术资料和书籍非常丰富,相比之下,有关Java虚拟机的资料却显得异常贫乏。 这种状况在很大程度上是由Java开发技术本身的一个重 要优点导致的:在虚拟机层面隐藏了底层技术的复杂性以及机器与操作系统的差异性。运行程序的物理机器的情况千差万别,而Java虚拟机则在千差万别的物理机上建立了统-的运行平台,实现了在任意一 台虚拟机上编译的程序都能在任何一台虚拟机上正常运行。这-极大优势使得Java应用的开发比传统CC++应用的开发更高效和快捷,程序员可以把主要精力集中在具体业务逻辑上,而不是物理硬件的兼容性上。在一般情况下,一个程序员只要了解了必要的JavaAPI. Java 语法