返回结果信息如下所示: Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at cn.zhengsh.jvm.oom.HeapOOM.main (JavaVMStackSOF.java:13) at cn.zhengsh.jvm.oom.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:14) // 省略更多 OutOfMemoryError package cn.zhengsh.jvm.oom; /** * @author zhengsh * @date 2021-08-13 */ public .test(JavaVMStackSOF2.java:22) at cn.zhengsh.jvm.oom.JavaVMStackSOF2.test(JavaVMStackSOF2.java:22) (DirectMemoryOOM.java:21) 参考资料 《深入理解 JVM 虚拟机-第三版》 周志明 https://docs.oracle.com/javase/specs/jls/se8/html
深入理解JVM - 实战JVM工具(上) 前言 这篇文章主要介绍一下常用的JVM工具,当然介绍这些工具是没有意义的,因为不去使用吃个饭基本就会忘光,所以这篇文章主要为使用工具实操一下大致如何监控和调优代码 解读日志是掌握JVM的基本功,在掌握基本的解读能力之后,这篇文章来讲述JVM的工具实战技巧。 「Zabbix,openfalcon,ganglia」 等测试工具 实战案例场景 注意,代码运行在「Jdk8」的版本上。 思考题: 做JVM调优的时候,可以根据下面的问题来进行思考: 你们公司有没有类似这里讲的JVM参数模板? 假如你是公司的架构师,结合你们公司的大部分业务系统的实际情况,会如何定制一套JVM参数模板? 是否你们公司有各种不同配置的机器? 针对不同配置的机器如何定制JVM参数模板?
实战 内存溢出定位与分析 环境搭建 /** * 模拟测试插入一百万条字符串[image.png](https://img.hacpai.com/file/2019/08/image-dd10de62 实战:死锁问题 构建死锁环境 public class TestDeadLock { // 定义两个锁 private static Object obj1 = new Object ; } } } } } 结果 [root@hadoop101 jvm]# javac TestDeadLock.java [root@hadoop101 jvm]# java TestDeadLock Thread1得到了obj1这把锁!
Java是面向对象的静态强类型语言,声明并创建对象的代码很常见,根据某个类声明一个引用变量指向被创建的对象,并使用此引用变量操作该对象 在实例化对象的过程中,JVM中发生了什么化学反应呢? 方法 <clinit>是类初始化时执行的方法 <init>是对象初始化时执行的方法 (2) 前面所述是从字节码的角度看待对象的创建过程,现在从执行步骤的角度来分析: ● 确认类元信息是否存在 当JVM 抛ClassNotFoundException 若有,转2 检查这个符号引用所代表的类是否已被JVM加载 若否,就找该类的class文件,并加载进方法区 若是,转3 根据方法区中该类的信息确定该类所需的内存大小 JVM在一个类被加载进方法区的时候就知道该类生产的每一个对象所需要的内存大小 从堆中划分一块对应大小的内存空间给新的对象,分配堆中内存有两种方式 指针碰撞(Bump the Pointer) 如果JVM 对齐补充(Padding) 2.1 对象头 存储对象在运行过程中自身所需要的一些数据 哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等 类型指针 即对象指向它的类元数据的指针,JVM
JVM是由一个对应角色的oop对象来描述Java对象 instanceOopDesc用来描述普通实例对象 arrayOopDesc用来描述数组对象 这些类型的oop对象均是继承自oopDesc。
如何在高性能服务器上进行JVM调优? 为了充分利用高性能服务器的硬件资源,有两种JVM调优方案,它们都有各自的优缺点,需要根据具体的情况进行选择。 1. 由于System.gc()只是建议JVM回收,JVM可能不马上回收内存,那么这时直接内存就抛出内存溢出异常,使得程序终止。 JVM崩溃的原因 当内存溢出时,JVM仅仅会终止当前运行的程序,那么什么时候JVM会崩溃呢? 什么是异步请求? 我们知道,Web服务器和客户端采用HTTP通信,而HTTP底层采用TCP通信。 异步请求如何造成JVM崩溃? 当TCP连接过多时,超过JVM的承受能力,JVM就发生崩溃。 如何处理大对象? 大对象对于JVM来说是个噩耗。
在这个过程中,JVM会初始化继承树上还没有被初始化过的所有父类,并且会执行这个链路上所有未执行过的静态代码块、静态变量赋值语句等。 某些类在使用时,也可以按需由类加载器进行加载。 在类加载器家族中存在着类似人类社会的权力等级制度 最高层的Bootstrap 在JVM启动时创建的,通常由与操作系统相关的本地代码实现,是最根基的类加载器,负责装载最核心的Java类,比如Object、 如何确立每个类在JVM的唯一性 类的全限定名和加载这个类的类加载器的ID 在学习了类加载器的实现机制后,知道双亲委派模型并非强制模型,用户可以自定义类加载器,在什么情况下需要自定义类加载器呢? 1 加载的定位 “加载”是“类加载”(Class Loading)过程的第一步1.1 加载的过程 在加载的过程中,JVM主要做3件事情 通过一个类的全限定名来获取定义此类的二进制字节流(class文件) ,JVM会创建一个java.lang.Class类的对象,作为本类的外部访问接口 既然是对象就应该存放在Java堆中,不过JVM规范并没有给出限制,不同的虚拟机根据自己的需求存放这个对象 HotSpot
在这个过程中,JVM会初始化继承树上还没有被初始化过的所有父类,并且会执行这个链路上所有未执行过的静态代码块、静态变量赋值语句等。 某些类在使用时,也可以按需由类加载器进行加载。 在类加载器家族中存在着类似人类社会的权力等级制度 最高层的Bootstrap 在JVM启动时创建的,通常由与操作系统相关的本地代码实现,是最根基的类加载器,负责装载最核心的Java类,比如Object AppClassLoader的Parent为Bootstrap,它是通过C/C++实现的,并不存在于JVM体系内,所以输出为 null ? 设置条件断点 JVM如何确立每个类在JVM的唯一性 类的全限定名和加载这个类的类加载器的ID 在学习了类加载器的实现机制后,知道双亲委派模型并非强制模型,用户可以自定义类加载器,在什么情况下需要自定义类加载器呢 ,JVM会创建一个java.lang.Class类的对象,作为本类的外部访问接口 既然是对象就应该存放在Java堆中,不过JVM规范并没有给出限制,不同的虚拟机根据自己的需求存放这个对象 HotSpot
深入理解JVM - 案例实战 主要业务: 问题: 初步排查: 初步排查FULL GC的套路有哪些:(重点) 继续排查: 解决方式: 总结: 主要业务: 问题分析: Problem Suspect 1 trance 链路追踪: 为什么String.split()会造成内存泄露 解决方式: 前言: 这一篇文章还是讲实战,但是内容并不是很多,下一篇会出一个阶段总结对于之前的内容进行回顾。 前文回顾 上一节深入扩展了JVM工具jstat是如何使用了,但是从实际场景可以看出,更多情况是代码的问题,或者因为好奇害死猫乱设置参数导致线上各种报错或者频繁的卡死,这里还是再次强调一句不要使用System.gc ()这个臭名昭著的方法,最好是JVM禁止此方法的运行。 发现原因是jvm缓存没有及时进行清理,导致内存越来越大 5. 排查结果是本地内存没有进行限制,同时没有定期淘汰算法 6.
Meter是由MeterRegistry创建和保存的,可以理解MeterRegistry是Meter的工厂和缓存中心,一般而言每个JVM应用在使用Micrometer的时候必须创建一个MeterRegistry 下面分节详细介绍这些类型的使用方法和实战使用场景。 ")); 表示忽略"http"标签,拒绝名称以"jvm"字符串开头的Meter。 另外,Prometheus已经内置了一个时序数据库的实现,因此,在做一套相对完善的度量数据监控的系统只需要依赖目标JVM应用,Prometheus组件和Grafana组件即可。 因此,这篇文章就是对Micrometer中的各种Meter的使用场景基于个人的理解做了调研和分析,分享一下实战中的经验和踩坑经历。
了解JVM内存结构的目的 在Java的开发过程中,因为有JVM自动内存管理机制,不再需要像在C、C++开发那样手动释放对象的内存空间,不容易出现内存泄漏和内存溢出的问题。 但是,正是由于把内存管理的权利交给了JVM,一旦出现内存泄漏和内存溢出方面的问题,如果不了解JVM是如何使用内存的,不了解JVM的内存结构是什么样子的,就很难找到问题的根源,就更难以解决问题。 JVM内存结构简介 在JVM所管理的内存中,大致分为以下几个运行时数据区域: 程序计数器:当前线程所执行的字节码的行号指示器。 JVM规范对这个区域的限制非常宽松,除了和Java堆一样不需要连续的内存和可以选择固定大小或者可扩展外,还可以选择不实现垃圾收集。 方法区用于存储已被JVM加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
OOP-Klass模型用来描述class的属性和行为 设计为OOP和Klass两部分是因为不希望每个对象都有一个C ++ vtbl指针, 因此,普通的oops没有任何虚拟功能。 相反,他们将所有“虚拟”函数转发到它们的klass,它具有vtbl并根据对象的实际类型执行C ++调度。
怎么避免死锁 死锁产生的四个必要条件 死锁产生的原因 如何避免死锁呢 如果在生产环境发生了死锁,我们将看到的是部署的程序没有任何反应了,这个时候我们可以借助 jstack进行分析,下面我们实战操作查找死锁的原因 jdk8u171\jre\lib\plugin.jar;E:\Java\jdk8u171\jre\lib\resources.jar;E:\Java\jdk8u171\jre\lib\rt.jar;E:\jvm-test \target\classes cn.zjq.jvm.TestDeadLock Thread1 拿到了 obj1 的锁! entry [0x000000001f49f000] java.lang.Thread.State: BLOCKED (on object monitor) at cn.zjq.jvm.TestDeadLock entry [0x000000001f39f000] java.lang.Thread.State: BLOCKED (on object monitor) at cn.zjq.jvm.TestDeadLock
前 言 作者简介:半旧518,长跑型选手,立志坚持写10年博客,专注于java后端 ☕专栏简介:实战案例驱动介绍JVM知识,教你用JVM排除故障、评估代码、优化性能 文章简介:介绍堆的相关概念 、教你排查5个常见的JVM堆案例实战 文章目录 6.堆 6.1 堆的特点 6.2 堆内存溢出问题 6.3 代码内存性能影响的评估 6.4 多次垃圾回收内存占用仍很高问题的排查 6.堆 6.1 堆的特点 StringConcatHelper.java:420) at MemoryOverFlow.main(MemoryOverFlow.java:12) 28 另:参数-Xmx 可以设置jvm free = 7714736 (7.3573455810546875MB) 8.033180236816406% used 重点查看uesd这一项,可以看到代码中内存的变化过程,这里JVM 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J3O31REj-1656678910765)(F:/%E5%8D%9A%E5%AE%A2%E5%9B%BE%E7%89%87/jvm
jvm最全详解-05-JVM调优工具详解及调优实战 前置启动程序 事先启动一个web应用程序,用jps查看其进程id,接着用各种jdk自带命令优化应用 Jmap 此命令可以用来查看内存信息,实例个数以及占用内存大小 / (路径) 示例代码: public class OOMTest { public static List<Object> list = new ArrayList<>(); // JVM 运行情况预估 用 jstat gc -pid 命令可以计算出如下一些关键数据,有了这些数据就可以采用之前介绍过的优化思路,先给自己的系统设置一些初始性的JVM参数,比如堆内存大小,年轻代大小,Eden和 尽量减少Full GC的频率,避免频繁Full GC对JVM性能的影响。 这种情况完全可以考虑采用一些成熟的JVM级缓存框架来解决,比如ehcache等自带一些LRU数据淘汰算法的框架来作为JVM级的缓存。
深入理解JVM - 实战老年代优化 前言 通过前面的文章可以了解到JVM优化中老年代的FULL GC对于系统以及垃圾收集器的行为有着十分大的影响,比如CMS并发标记或者回收撑不住的时候要暂停用户线程并且呼叫 综上所述,老年代的优化是JVM优化的一个核心知识点,所以这一节就来讲解如何优化老年代的回收,尽量让对象在新生代回收而不是在老年代进行回收。 ,这篇文章则根据前面的知识点,根据一个模拟的案例来讲解一下如何对于JVM老年代进行调优。 案例实战 案例实战会根据一个非常理想化的模拟场景,因为应用的性能实际上会有各种的影响,甚至代码的质量也会影响系统的运行性能,所以下面的模拟场景均为假想的情况,切勿过于认真的对待这个案例的各种参数。 如果是4核心8G的机器,则分4G给JVM,4G中分1G给虚拟机栈500M多M,方法区:256M,堆外内存给256M。
在生产环境中执行的应用程序当出现响应时间慢以及过于频繁的GC,那么此时就需要收集JVM运行的数据来分析是什么原因导致了应用程序响应时间慢,也许在这个过程中出现了大量的文件I/O加载导致都有可能导致程序出现内存泄露等情况 特别是在企业级的生产环境中,在出现问题的时候很难使用主流的可视化工具来查看JVM运行过程中的数据,此时可以使用jstat命令工具来收集JVM运行过程中的数据,下面详细地阐述jstat命令行工具的案例应用与实战 jstat全称为JVM Statistics Monitoring Tool,它主要用于收集JVM在执行过程中运行的各种数据,如垃圾收集,GC次数以及YGC、YGCT等数据。 -gcold:监视老生代GC状况 -gcutil:输出的内容与“-gc”基本一致,重点关注已使用空间占总空间的百分比 -class:监视类装、卸载数量、总空间、类装载所消耗费的时间 jstat案例实战 判断是否内存泄露 在jstat命令行工具中可以根据如下的思路来判断是否可能出现了内存泄露,具体思路如下: 运行中的Java程序,运行jstat命令行工具获取JVM运行的数据,重点关注OU值的数据(OU
jdk8u171\jre\lib\plugin.jar;E:\Java\jdk8u171\jre\lib\resources.jar;E:\Java\jdk8u171\jre\lib\rt.jar;E:\jvm-test \target\classes cn.zjq.jvm.TestJvmOutOfMemory java.lang.OutOfMemoryError: Java heap space Dumping heap AbstractStringBuilder.java:448) at java.lang.StringBuilder.append(StringBuilder.java:136) at cn.zjq.jvm.TestJvmOutOfMemory.main
前 言 作者简介:半旧518,长跑型选手,立志坚持写10年博客,专注于java后端 ☕专栏简介:实战案例驱动介绍JVM知识,教你用JVM排除故障、评估代码、优化性能 文章简介:介绍JVM的作用 、JVM、JRE、JDK的区别,常见的JVM与JVM学习路线 文章目录 1.JVM简介 1.1 JVM的作用 1.2 JVM、JRE、JDK 1.3 常见的JVM 1.4 JVM的学习路线 2.程序计数器 1.JVM简介 1.1 JVM的作用 JVM的作用如下: 一次编写,处处运行 自动管理内存,垃圾回收 数组下标越界检查,如果允许使用数组下标越界的内存分配方式,那么就可能出现内容覆盖的情况,因此JVM 1.2 JVM、JRE、JDK 三者的区别、联系如下图。 1.3 常见的JVM JVM遵守一系列规范,如有需要,可以自己开发一个JVM,很多大公司有自己的JVM,常见的JVM如下表。 1.4 JVM的学习路线 如下图,JVM主要包括三个部分:类加载器,JVM内存结构与执行引擎。一个类经过编译后,必须有类加载器进行加载。
前 言 作者简介:半旧518,长跑型选手,立志坚持写10年博客,专注于java后端 ☕专栏简介:实战案例驱动介绍JVM知识,教你用JVM排除故障、评估代码、优化性能 文章简介:介绍方法区概念 7.9 直接内存的内存溢出问题 直接内存direct memory并不由jvm进行垃圾回收,可能导致内存泄漏问题。运行如下代码。 DirectByteBuffer.java:123) at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311) at cn.itcast.jvm.t1 因此,直接内存的回收其实不是由jvm虚拟机完成,而是通过Unsafe对象调用freeMemory()完成。 下面查看ByteBuffer类的源码来验证我们的观点。 7.10 禁用显式垃圾回收对直接内存的影响 在java中可以采用System.gc()来显式的建议jvm进行垃圾回收,但这种垃圾回收方式是Full GC,既会进行新生代的回收,也会进行老年代的回收。