jvm讲解

说明 jvm整体的介绍、解决项目中的问题。 垃圾回收 先介绍(其他部分只是做了简单的说明) -》 垃圾回收 -》 解决项目中的问题( 常用的工具、命令、参数配置)(通用的方式、其他)-》 其他 -》 分期:jvm我们常用的就是性能分析和高并发(本次暂时不讲)。其他部分如果分期去讲,其实不常用而且很枯燥,但是其思路还是值得去了解一下,且会依赖这部分但是依赖性不强。 如果为特别说明版本默认是HotSpot的jdk1.7。,虽然版本不同但总体思路差不多。 概述 Jvm:J就是java vm指虚拟机。它只是认识class文件。 程序编译与代码优化、类加载 i++与++I 区别?性能比较。 也可看字节码Ijiajia.java。前期和后期

高并发 线程安全 “不可变”--final、 绝对线程安全--“不管运行时环境如何,调用者都不需要任何额外的同步措施” 相对线程安全--只需要保证对个对象单独的操作是线程安全的,但对于一些特定顺序的连续调用,就可能需要额外的同步手段。 VectorTest.java isRequestOverload方法

锁 synchronized 这是原生的,性能方面已经被优化过了(自旋、轻量级锁)。使用阻塞式的锁时可以优先考虑。 cas缺点和结合代码 SnmpV3Server.java dealCacheMsg方法 两次 SnmpProcess.ryBatchInsertWithSafe 两次 一条告警4次

垃圾回收 内存分配 程序计数器 当前线程所执行的字节码的行号。字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转等。线程私有。生命周期与线程一致。 栈 虚拟机栈描述的是java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。

局部变量表存放了编译期可知的各种基本数据类型、对象引用类型(不是对象本身,可能是个引用) 线程私有。生命周期与线程一致。 本地方法栈 与栈发挥的作用非常相似。虚拟机栈为虚拟机执行java方法服务,而本地方法栈这是Native方法服务的。线程私有。生命周期与线程一致。

Java堆 几乎所有的对象实例都放在这里。由于现在的收集器都是采用分代收集算法,所以还可以细分为新生代和老年代;再细致一点有Eden空间、From Survivor空间、To Survivor空间等 方法区 用于存储已被虚拟机加载的类信息、常量、静态变量、及时编译器编译后的代码等数据。对于其他虚拟机并不存在永久代概念,是因为HotSpot设计团队为了省去麻烦把堆上的分代收集的方式扩展至方法区来了, 所以这部分通常有人称为永久代。数据也并非永久存在。主要是针对常量池的回收和对类型的卸载。(现网那个问题就是出现在这个区域) 元空间 Java8,永久代被替换为元空间。 -XX:MetaspaceSize 初始空间配额,达到该值就会触发垃圾回收,同时还会对该值进行调整。 -XX:MaxMetaspaceSize 分配的最大空间,默认是没有限制的。可以无限(直到内存使用完)

Ccs:Compressed Class Space 使用的压缩优化技术之一。 可以通过-XX:+UseCompressedClassPoints参数来控制开启还是关闭。默认开启。通过-XX:CompressedClassSpaceSize指定大小默认是1G。压缩指针,指的是在64位机器上,使用32位的指针来访问数据的一种方式。可以节约内存。

我们项目中配置的jvm参数 修改该/home/bms/OpenAS_Tomcat/bin/shutdown.sh文件中的配置 Jdk1.7 -Xms1024m -Xmx4096m -XX:NewRatio=4 -XX:PermSize=2048m -XX:MaxPermSize=4096m Jdk1.8

运行时常量池 是方法区的一部分。具备动态性,及java语言不要求常量一定只有编译期才能产生,运行期也可能将新的常量放入池中。 直接内存 并不是java虚拟机规范中定义的内存区域,但这部分内存也被频繁的使用,而且也可能导致OOM异常。NIO方面的东西会使用到,避免在java堆于Native堆中来回复制数据。 直接内存的分配不会受到java堆大小的限制,配置虚拟机参数时经常容易忽略直接内存,使得各区域内存总和大于物理内存限制从而导致动态扩展时OOM。 小结 JVM内存计算 一个 Java 进程的内存大致 = 进程自身内存 + JVM Heap 区 + JVM Metaspace + Java NIO 进程自身内存:用来处理进程基本开销,很小,估计100M JVM Heap 区:由-Xms –Xmx参数指定 JVM Metaspace:CompressedClassSpaceSize、code cache等 实际使用 Metaspace 大小包括了CompressedClassSpaceSize

YGC Eden Space和Survivor Space都属于新生代,新生代中执行的垃圾回收被称之为Minor GC(因为是对新生代进行垃圾回收,所以又被称为Young GC)

分代 Eden Space字面意思是伊甸(dian)园,在《圣经》耶和华神在东方的伊甸建了一个美丽花园,把刚造出来的人安置在这个园子里。Jvm把新创建的一些对象被创建的时候首先放到这个区域,进行垃圾回收后,不能被回收的对象被放入到空的survivor区域。

Survivor Space幸存者区,用于保存在eden space内存区域中经过垃圾回收后没有被回收的对象。Survivor有两个,分别为To Survivor、 From Survivor,这个两个区域的空间大小是一样的。执行垃圾回收的时候Eden区域不能被回收的对象被放入到空的survivor(也就是To Survivor,同时Eden区域的内存会在垃圾回收的过程中全部释放),另一个survivor(即From Survivor)里不能被回收的对象也会被放入这个survivor(即To Survivor),然后To Survivor 和 From Survivor的标记会互换,始终保证一个survivor是空的。

1长期存活的对象进入老年代 虚拟机给每个对象定义了一个对象年龄计数器,如果对象在Eden出生并经过一次YGC,则年龄加1,到达阈值就会被晋升到老年代。通过-XX:MaxTenuringThreshold设置,默认值为15岁。 为了更好地适应不同程序的内存状况,虚拟机并不是永远地要求对象的年龄必须达到了MaxTenuringThreshold才能晋升到老年代。如果幸存者区相同年龄所有对象大小的总和大于幸存者空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代。 2大对象直接进入老年代 大对象需要大量连续内存空间的对象(如很长的字符串、数组),特别是遇到一群大对象而且存在时间很短,这对虚拟机来说是一个“坏消息”,容易还有不少空间时就提前触发垃圾收集器来获取足够连续的空间。 虚拟机提供-XX:PretenureSizeThreshold参数,大于这个设置值的对象直接进入老年代。避免Eden区以及两个幸存者区发生大量的内存复制。 3空间分配担保 在发生YGC之前,会先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果成立则执行YGC,如果不成立则会查看HandlePromotionFailure参数是否允许担保失败,如果允许,那么会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试进行一次YGC。否则进行FGC。即当survivor区不够则会向老年代借用一部分内存,用完了还要还的。 4老年代和永久代 Sun的Hotspot虚拟机老年代和永久代基本是一个。

检查对象已死方式 引用计数算法 Jvm没有采用。主要原因是他很难解决对象之间相互循环引用问题 RefGc.java 可达性分析算法 通过一系列的称为“GC Roots”的对象作为起始点,当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。

可作为GC Roots对象 包括下面几种: 虚拟机栈(栈帧中的本地变量表)中引用的对象。 方法区中类静态属性引用的对象。 方法区中常量引用的对象。 本地方法栈中JNI(即一般说的Native方法,Java Native Interface)引用的对象。

引用 强引用:就是指在代码中普遍存在的,类似“Object object = new Object()”这类的引用,只要强引用存在,垃圾收集器永远不会回收掉被引用的对象。 软引用:一些有用但并非必须的对象。在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围中。 弱引用:用来描述非必需的对象,被弱引用关联的对象只能生存到下一次垃圾收集发生之前,当垃圾收集器工作时,无论当前内存是否足够,都会被回收掉。缓存方面可以用。 虚引用:是弱的一种引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间够长影响,也无法通过虚引用来取得一个对象实例。它的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。

垃圾收集算法 标记-清除算法 缺点1:效率问题,标记和清除两个过程的效率都不高 缺点2:标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后需要分配大对象时,无法有足够的连续内存而不得不提前触发另一次垃圾收集动作。

复制算法 缺点1:内存缩小了为原来的一半。但由于新生代中的对象98%都是“朝生夕死”的,所以可以按8:1:1的比例来分配。这样内存浪费的比较少了。 缺点2:在对象存活率较高时就会进行较多的复制操作。 标记-整理算法 分代收集算法 根据不同的年龄带采用不同的垃圾收集算法。复制算法适用新生代,标记-清除或标记整理适用老年代。

垃圾收集器 垃圾收集算法是理论,垃圾收集器是具体的实现。

G1 Garbage-First,是当今收集器技术发展的最前沿成果之一,“化整为零”的思路。具有以下特点 并行与并发 并行是指两个或多个task同时执行用以完成同一个计算任务,例如使用两个线程来并行地完成矩阵乘运算。

并发是指两个或多个task同时执行,但是彼此相互独立、分别在完成不同的计算(这里的task不仅仅局限于线程,它也可以代表纤程、进程等) 分代收集 还是使用了分代收集算法 空间整合 复制算法和标记-整理 可预测的停顿 G1除了追求降低停顿时间外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒。

性能监控工具 命令行工具 如果要查看比较复杂的指标,可以借助一些可视化工具如 查看pid 属于linux自带的命令 ps -ef|grep java

查看jvm参数 jps -v

jvm执行gc的信息每秒钟刷新一次 jstat -gc 73635 1000

图中说的单位是字节 但是自己试过了图中单位是kb。并不是B

jvm类加载的个数每秒钟刷新一次 jstat -class 73635 1000

查看虚拟机当前时刻内所有正在执行的线程 如查看是否有死锁。死锁一定就会导致cpu过高? jstack 29137 > test.txt

查看jvm存活的实例 jmap -histo:live 29131 > live.txt

Live.txt就是一个实例。

jvm堆转储快照 可以查看占用内存最大的对象等详细信息,生成的快照比较大 ,且分析时候会占用许多资源。将快照放在另外的环境上去分析。 jmap -dump:format=b,file=test.bin 29137

项目中

之前的wiki

当虚拟机内已经出现oom异常了,接下来日志里面出现的oom其实是不准确的 复现与分析也是同等重要的。

增加约150m GCT:gc占用的总时间单位秒 jstat -gc 73635 1000

分析中可能会发现很多问题都会导致,这个时候依次解决。如时间比较仓促。

其他 规范以及和规范相关的。 规范 oracle事务要保证、主键不能为空、。findOne方法。 DefThreadFactory捕获异常 就像车一样可以定期去整改、大改,自己觉得LLT与自动化

相关 架构满足的目标之一“非公能性需求九维目标” 高性能、稳定性、可用性、安全性、灵活性、易用性、可靠性、可扩展性、可维护性 可靠性:业务数据和流程一致,比如用户的资金结算不能算错。 可用性:系统在时间内提供服务能力的概率值。 具体。比如

大数据方面 这其实和遗留系统重构联系比较紧密(几年前开始思考如何对其重构)。我们系统已经可以称为遗留系统了(孙他们的系统也在逐步进行改善),在不能对其重构的情况下即不能使用其他的工具。没有必要的情况下,可以借鉴其思路来解决问题。还是以项目中的实例为基础,列举两种 实例 提升性能优化通常的思路都是尽量的压缩数据量而不是使原有的数据成倍的增长,以这次的告警分周表和月表和总表。 联合索引 用于数据库 Bitset 压缩方式 用于代码,还有其他压缩思路。如增量、行转列(时间) Fst

本文内容来源《深入理解java虚拟机》第二版 周志明著、有部分内容来自互联网、部分内容属于原创。

补充: 找到进程对应的类 jmap -histo 6094 Arthas

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秋天的猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值