Java进阶营Java技术专题-虚拟机参数基础学习

Posted 澎湖Java

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java进阶营Java技术专题-虚拟机参数基础学习相关的知识,希望对你有一定的参考价值。

JVM参数简介

-XX参数被称为不稳定参数,之所以这么叫是因为此类参数的设置很容易引起JVM 性能上的差异,使JVM 存在极大的不稳定性。如果此类参数设置合理将大大提高JVM 的性能及稳定性。

例如:-XX:+PrintGCDetail,-XX:+ParallelGC

不稳定参数语法规则

布尔类型参数值

-XX:+ '+'表示启用该选项
-XX:- '-'表示关闭该选项

数字类型参数值:

-XX:= 给选项设置一个数字类型值,可跟随单位,

例如:'m’或’M’表示兆字节;'k’或’K’千字节;'g’或’G’千兆字节。32K与32768是相同大小的。-XX:MaxMetaspaceSize=1000m、-XX:newRadio=3

字符串类型参数值

-XX:= 给选项设置一个字符串类型值,通常用于指定一个文件、路径或一系列命令列表。

例如:-XX:HeapDumpPath=./dump.core

FullGC出现前后打印日志

当出现了FullGC的时候,最需要我们注意的就是如何在指定的时间点,进行生产对应的heap dump文件以及对应的当前的快照信息。

JVM参数实现在Full GC前后自动生成Dump。共有三个VM参数需要设置:

1.**HeapDumpBeforeFullGC **实现在Full GC前dump。
2.**HeapDumpAfterFullGC **实现在Full GC后dump。
3.HeapDumpPath设置Dump保存的路径

设置这些参数的方法,这里总结了四种,大家可以根据情况选择使用。

方法1

启动jvm时,带上这些参数(这个方法适合开发测试环境)

Java -Xms200m -Xmx200m -Xmn50m -XX:PermSize=30m -XX:+HeapDumpBeforeFullGC -XX:+HeapDumpAfterFullGC -XX:HeapDumpPath=e:\\dump -jar xxx.jar

方法2

使用JConsole等工具调用JMX服务的com.sum.management.HotSpotDiagnostic.setVMOption方法来实现。在此我向大家推荐一个架构学习交流圈。交流学习指导伪鑫:1253431195(里面有大量的面试题及答案)里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

  • 第一个参数为HeapDumpBeforeFullGC, 第二个参数为true表示在Full GC前进行dump.

  • 第一个参数为HeapDumpAfterFullGC, 第二个参数为true表示在Full GC前进行dump.

方法3

使用 **jinfo **命令进行设置。(生产环境常用的方法)

调用jinfo命令设置VM参数

# jinfo -flag +HeapDumpBeforeFullGC 5940

# jinfo -flag +HeapDumpAfterFullGC 5940

方法4

开发程序调用JMX的API来实现,得到了Full GC前后的dump, 接下来就可以使用一些分析工具(如MAT)来分析Full GC产生的原因了

Java堆溢出

堆是用来存储对象的,如果创建了大量的对象且这些对象得不到及时的回收就会造成内存占满,抛出OOM(GC回收时间超过阈值的百分之98% 并且回收的内存不到2%)

怎么解决

设置JVM参数,Dump出当前的内存堆转储快照

解决办法见思路


虚拟机栈和本地方法栈溢出

对单个线程来说:HotSpot将两个栈合二为一,栈里面存储的是栈帧,只有当栈帧不断压入栈(函数递归)就会栈溢出,此时栈深度过深:StackOverflowError。或者一个方法的变量太多导致栈帧内存太大,是的栈的内存不足,很快溢出OutOfMemoryError。

内存溢出:就是栈所占用内存和数量太多了,同时也侧面看出来创建的线程数量太多了,导致OOM。

解决办法

单线程来说:避免栈溢出

1. 找到递归函数,减少递归次数
2. 减少函数本地变量个数以及大小,相应的缩小栈帧的大小
3. 通过-Xss命令来扩大栈内存容量

多线程造成的OOM

1. 减少线程创建数量,优先使用线程池
2. 如果是在不能减少线程,可以适当的减少虚拟机栈的内存来增加可容纳的线程数


方法区和运行时常量池溢出

方法区存放的是类信息和运行时常量池

如果创建大量的类

(因为类的回收要求比较严格,所以一旦创建大量的类,得不到及时回收就会内存溢出)在项目中使用动态代理CGlib技术会生成大量的类,很多动态语言都是这么实现的,因为类加载机制,不同的加载器加载出的同一个类,JVM会认为不同且都保留。在此我向大家推荐一个架构学习交流圈。交流学习指导伪鑫:1253431195(里面有大量的面试题及答案)里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

如果创建大量的常量且放入常量池

**String类中的intern()方法就是一个Native方法,它的作用是:如果字符串常量池中已经包含一个String对象的字符串(地址),则返回代表池中这个字符串的String对象地址;**否则,将此String对象包含的字符串添加到heap堆中,并且返回此字符串常量池的String对象的引用。

直接内存溢出

DirectMemory容量可以通过**-XX:MaxDirectMemorySize指定,如果不指定,则默认与Java堆最大值(-Xmx**指定)一样。

虽然使用DirectByteBuffer分配内存也会抛出内存溢出异常,但它是并没有真正向操作系统申请分配内存,而是通过计算得知内存无法分配,手动抛出的内存异常。


-XX:MaxDirectoryMemorySize
-XX:MaxMetaSpaceSize
-XX:NewSpaceSize/-Xmx
-Xss
-XX:+HeapDumpOnOutOfMemoryError

在运行的时候设置JVM参数,使其Dump出内存异常信息

-XX:+HeapDumpOnOutOfMemoryError,当出现OOM异常的时候,我们就可以看到一场JVM打印的异常信息

通过内存映像分析工具(Eclipse Memory Analyzer)对Dump出来的内存转储快照进行分析

内存泄漏(Memory Leak)
内存溢出(Memory Overflow)

确定是哪种情况之后

如果是内存泄漏,可进一步通过工具查看泄漏对象到GC Roots的引用链,看看对象时通过怎样的路径与GC Roots相关联导致垃圾收集器无法自动回收他们,掌握了泄露对象的类型信息以及GC Roots引用链信息,就可以比较准确的定位泄漏的位置。

如果不存在泄漏,就说明这些对象都是应该存活的,但是内存不够大。这时候就需要调整堆内存的大小,对比机器物理内存看看堆内存能否相应的调大一点,从代码上检查是否存在某些对象生命周期过长、持有状态时间过长的情况,尝试减少程序运行期的内存消耗。

Java虚拟机,这是值得你去进阶的方向

而随着时间的推移,慢慢地大家都逐渐步入到了中级程序员的等级,同时也有越来越多的人感觉到了焦虑,因为不学习就意味着原地踏步,虽然目前自己的技术水平可能已经挺不错了,可还是不敢长时间停留,逆水行舟中,不进则退。

因此,几乎每一天都会不断地有朋友反反复复地问我这同一个问题:“基础已经学完了,想进一步提升,该如何学习?” 我也基本能理解大家的心情。

对于这个问题,我真的很想找到一个标准答案,然后复制粘贴给每一个提问的人,但是这个问题却永远没有一个标准答案。因为技术的领域实在是太广阔了,世界上没有任何一个人能把所有的技术全部都学会,想进阶首先你要认准一个方向才行,而不是盲目地焦虑该如何进一步提升自己。

那么进阶的方向有哪些呢?这个就太多了,不同的项目侧重的技术点也不一样。比如IM软件就需要即时通讯技术、视频软件就需要视频编解码技术、游戏就需要引擎技术。即使是同一个项目,每个人负责的工作方向也会不一样,有些人负责架构搭建,有些人负责网络通信,有些人负责UI实现。因此,这些都是进阶的方向,学习自定义View也叫进阶,学习设计模式也叫进阶。

Java虚拟机重要吗?重要。我们平时关注的内容大多是在语言层面上的,至于底层到底是如何运行的则很少有人关注。然而,不管是从事Java也好、Android也好,工作到一定层次之后遇到的一些问题确实是需要了解Java虚拟机才能解决的。

比如说内存泄漏,这是一个很常见又很让人苦恼的问题。之所以这个问题难查,还是因为大多数人对Java虚拟机底层的内存管理机制并不熟悉。而如果我们深入地了解了Java虚拟机的垃圾收集器和内存分配策略,就可以更加得心应手地解决内存泄漏的问题。

再比如说现在Android领域中比较火的热修复、插件化等技术,都大量使用到了Java虚拟机中的类加载机制,从事这部分技术研发的人,如果对Java虚拟机技术不熟悉的话,那肯定是寸步难行的。

而且还有很重要的一点,Java虚拟机技术是不用担心过时的,因为不管未来Android程序是用Java开发也好、Kotlin开发也好,底层的运行环境都是依赖于Java虚拟机的。当然在Android上是叫ART,但本质上仍然是Java虚拟机。

这里我又要提到我的一个朋友了,去年以一个专科生的身份进了阿里,这看上去简直就是个奇迹,因为他同组的同事基本都是北大复旦毕业的。但是看似奇迹的背后其实靠的是他出色和扎实的技术功底,其中丰富的Java虚拟机知识在面试的时候就帮了他很大的忙。

这次极客时间找我来推广的《深入拆解Java虚拟机》这门课程,原本是给了我一篇推广用的通稿,我说会对通稿内容改一改。结果有感而发,写着写着就写出了这么一大段内容出来,最后通稿也没用上。可能也是因为产生了共鸣吧,Java虚拟机方面的内容确实是我下半年的学习计划,也是希望这部分内容能引起大家普遍的重视。

至于《深入拆解Java虚拟机》这门课程到底怎么样?讲师郑雨迪目前是甲骨文实验室的高级研究员,加入甲骨文之前,是在瑞士卢加诺大学攻读博士学位,专门研究如何更加精准地监控Java程序,以便做出更具针对性的优化。因此,讲师在Java虚拟机方面的实力是毋庸置疑的。

而课程的内容主要分为以下四大模块:

  • 基本原理:剖析Java虚拟机的运行机制,逐一介绍Java虚拟机的设计决策以及工程实现。

  • 高效实现:探索Java编译器,以及内嵌于Java虚拟机中的即时编译器,帮助你更好地理解Java语言特性,继而写出简洁高效的代码。

  • 代码优化:介绍如何利用工具定位并解决代码中的问题,以及在已有工具不适用的情况下,如何打造专属轮子。

  • 虚拟机黑科技:介绍甲骨文实验室近年来的前沿工作之一GraalVM。包括如何在JVM上高效运行其他语言,如何混搭这些语言,如何将这些语言事前编译成机器指令单独运行。

如果这些内容正是你所关注的,那么就毫不犹豫地加入吧,现在报名还能享受限时优惠价,只需45元,下周六就会恢复原价。

长按下图 -> 识别图中二维码 即可加入

以上是关于Java进阶营Java技术专题-虚拟机参数基础学习的主要内容,如果未能解决你的问题,请参考以下文章

Java虚拟机,这是值得你去进阶的方向

深入理解JVM虚拟机5:虚拟机字节码执行引擎

深入理解JVM虚拟机4:Java class介绍与解析实践

深入理解JVM虚拟机开篇:JVM介绍与知识脉络梳理

深入了解JVM虚拟机8:Java的编译期优化与运行期优化

java 基础知识学习 JVM虚拟机参数配置