java虚拟机之JVM调优详解

JVM常用命令行参数

1. 查看参数列表

虚拟机参数分为基本和扩展两类,在命令行中输入 JAVA_HOME\bin\java就可得到基本参数列表。
在命令行输入 JAVA_HOME\bin\java –X就可得到扩展参数列表。

2. 基本参数说明:

  • -client,-server: 两种Java虚拟机启动方式,client模式启动比较快,但是性能和内存管理相对较差,server模式启动比较慢,但是运行性能比较高,windos上采用的是client模式,Linux采用server模式
  • -classpath -cp: 虚拟机在运行一个类的时候,需要将其转入内存中,虚拟机搜索类的方式和顺序:Bootstrap classes、Extension classes、User classes。
  • Bootstrap 中的路径是虚拟机自带的 jar 或 zip 文件,虚拟机首先搜索这些包文件,用System.getProperty(“sun.boot.class.path”)可得到虚拟机搜索的包名。
  • Extension 是位于 jre\lib\ext 目录下的 jar 文件,虚拟机在搜索完 Bootstrap 后就搜索该目录下的 jar 文件。用 System. getProperty("java.ext.dirs”)可得到虚拟机使用
  • Extension 搜索路径。
  • User classes 搜索顺序为当前目录、环境变量 CLASSPATH、-classpath。
  • -classpath: 告诉虚拟机搜索目录名、jar文档名、zip文档名
  • -verbose[:class|gc|jni]: 在输出设备上显示虚拟机运行信息
  • -verbose:class 输出虚拟机装入的类的信息
  • -verbose:gc 在虚拟机发生内存回收时输出设备信息,用来监视虚拟机内存回收的情况
  • -verbose:jni 虚拟机调用native方法时输出设置显示信息,用来监视虚拟机调用本地方法的情况
  • -version:显示可运行的虚拟机版本信息
  • -showversion:显示版本信息以及帮助信息

3. 扩展参数说明:

  • -Xmixed: 设置 -client 模式虚拟机对使用频率高的方式进行 Just-In-Time 编译和执行,对其他方法使用解释方式执行,该方式是虚拟机缺省模式
  • -Xint: 设置-client模式下运行的虚拟机以解释方式执行类的字节码,不将字节码编译为本机码,有可能会损失性能
  • -Xbootclasspath:path、-Xbootclasspath/a:path、-Xbootclasspath/p:path: 改变虚拟机装载系统运行包 rt.jar,而从-Xbootclasspath 中设定的搜索路径中装载系统运行类。除非你自己能写一个运行时,否则不会用到该参数。
  • /a:将在缺省搜索路径后加上 path 中的搜索路径。
  • /p:在缺省搜索路径前先搜索 path 中的搜索路径。
  • -Xnoclassgc: 关闭虚拟机对 class 的垃圾回收功能,有可能会导致OutOfMemoryError
  • -Xincgc: 启动增量垃圾收集器,缺省是关闭的,增量垃圾收集器能减少偶然发生的长时间的垃圾回收造成的暂停时间,但增量垃圾收集器和应用程序并发执行,会占用部分CPU在应用程序上的功能
  • -Xloggc:file: 将虚拟机每次垃圾回收的信息写到日志文件中,文件名由file指定,文件格式是平文件,内容和-verbose:gc 输出内容相同
  • -Xms20M: 设置虚拟机可用内存堆的初始大小为20M,大小为1024的整数倍并且要大于1MB,可用K或者M为单位来设置较大内存数,初始堆大小为2MB,例如:-Xms256M
  • -Xmx20M: 设置虚拟机内存堆的最大可用大小,该值必须为1024的整数倍,并且要大于2MB,可用K或者M为单位来设置较大的内存数,例如:-Xmx81920K,-Xmx80M,当应用程序申请了大内存运行时虚拟机抛出 java.lang.OutOfMemoryError,就需要使用-Xmx来设置了
  • -Xss128K: 设置线程栈的大小,和-Xmx类似,可以用K或M来设置较大的值,也可以在Java中创建线程对象时设置栈的大小
  • -Xoss128k: 设置本地方法栈的大小为128K,不过HotSpot不区分虚拟机栈和本地方法栈,所以这个参数对于HotSpot是无效的
  • -XX:PermSize=10M: 表示JVM初始分配的永久代的容量,必须以M为单位
  • -XX:MaxPermSize=10M: 表示JVM允许分配的永久代的最大容量,必须以M为单位,大部分情况下这个参数默认为64M
  • -XX:NewRatio=4: 表示设置年轻代:老年代的大小比值为1:4,这意味着年轻代占整个堆的1/5
  • -XX:SurvivorRatio=8: 表示设置2个Survivor区:1个Eden区的大小比值为2:8,这意味着Survivor区占整个年轻代的1/5,这个参数默认为8
  • -Xmn20M: 表示设置年轻代的大小为20M
  • -XX:+HeapDumpOnOutOfMemoryError: 表示可以让虚拟机在出现内存溢出异常时Dump出当前的堆内存转储快照
  • -XX:+UseG1GC: 表示让JVM使用G1垃圾收集器
  • -XX:+PrintGCDetails: 表示在控制台上打印出GC具体细节
  • -XX:+PrintGC: 表示在控制台上打印出GC信息
  • -XX:PretenureSizeThreshold=3145728 表示对象大于3145728(3M)时直接进入老年代分配,这里只能以字节作为单位
  • -XX:MaxTenuringThreshold=1: 表示对象年龄大于1,自动进入老年代

虚拟机参数分类

标准: - 开头,所有的HotSpot都支持
非标准:-X 开头,特定版本HotSpot支持特定命令
不稳定:-XX 开头,下个版本可能取消

例如:java -version、java -X

import java.util.List;
import java.util.LinkedList;

public class HelloGC {
  public static void main(String[] args) {
    System.out.println("HelloGC!");
    List list = new LinkedList();
    for(;;) {
      byte[] b = new byte[1024*1024];
      list.add(b);
    }
  }
}

  • 区分概念:内存泄漏memory leak,内存溢出out of memory
  • java -XX:+PrintCommandLineFlags HelloGC
  • java -Xmn10M -Xms40M -Xmx60M -XX:+PrintCommandLineFlags -XX:+PrintGC HelloGC
  • PrintGCDetails PrintGCTimeStamps PrintGCCauses
  • java -XX:+UseConcMarkSweepGC -XX:+PrintCommandLineFlags HelloGC
  • java -XX:+PrintFlagsInitial 默认参数值
  • java -XX:+PrintFlagsFinal 最终参数值
  • java -XX:+PrintFlagsFinal | grep xxx 找到对应的参数
  • java -XX:+PrintFlagsFinal -version |grep GC

调优前的基础概念

1. 吞吐量: 用户代码时间 /(用户代码执行时间 + 垃圾回收时间)
2. 响应时间: STW(Stop The World)越短,响应时间越好

所谓的调优,首先自己要明确,想要的是什么,是吞吐量还是响应时间,还是在满足一定的响应时间的情况下,要求达到多大的吞吐量,一般来说根据业务类型去选择对应的调优方式,比如网站需要的是响应时间优先,JDK1.8尽量选G1,那如果是数据挖掘的需要使用的是吞吐量。

什么是调优

在没有接触过调优之前我们理解的JVM调优就是解决OOM问题,OOM只是JVM调优的一部分

一般是根据需求进行JVM规划和预调优优化运行JVM运行环境(慢,卡顿)解决JVM运行过程中出现的各种问题(OOM)

首先的话,调优是从业务场景开始的,如果没有业务场景的JVM调优都是不靠谱的,比如有时间在实际项目中,有很多个类,成千上万个代码,你怎么知道具体是哪个代码有问题,就算我们知道有段代码频繁的full gc,但是可能过一段时间就OOM了。

1.调优步骤:

  • 熟悉业务场景,选定垃圾回收器(没有最好的垃圾回收器,只有最合适的垃圾回收器)
  • 响应时间、停顿时间 [CMS G1 ZGC] (需要给用户作响应)吞吐量 = 用户时间 /( 用户时间 + GC时间) [PS]
  • 选择回收器组合
  • 计算内存需求(设置内存大小 1.5G 16G)
  • 选定CPU:越高越好
  • 设定年代大小、升级年龄
  • 设定日志参数

-Xloggc:/opt/xxx/logs/xxx-xxx-gc-%t.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=20M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCCause或者每天产生一个日志文件

在生产环境中日志文件,后面日志名字,按照系统时间产生,循环产生,日志个数五个,每个大小20M,这样的好处在于整体大小100M,能 控制整体文件大小

观察日志情况

2.调优案例

2.1案例一

垂直电商,最高每日百万订单,处理订单系统需要什么样的服务器配置

这个问题比较鸡肋,因为很多不同的服务器配置都能够支撑

比如有一百万个订单,每个小时不会产生很高的并发量,我们寻找高峰时间,做一个假设100W订单有72W订单在高峰期产生,比如一个小时平均36W订单,所以我们内存选择大小是按照巅峰时间选择的,很多时间我们可能就是去做压测,实在不行就添加CPU和内存

2.2案例二

12306遭遇春节大规模抢票应该如何支撑

订单信息每天固定,可以丢到缓存中,不同的业务逻辑有不同的业务设计,12306应该是中国并发量最大的秒杀网站,号称并发100W,就是说每秒进行百万次的业务逻辑的处理,估计淘宝一年最高的是54W并发。

如果解决这个问题呢,看下面所示:

CDN -》 LVS -》 NGINX -》 业务系统 -》每台机器1W并发

普通电商的下单流程一般是:

订单 -》下单-》 订单系统减库存 -》 等待用户付款

这个事务如果同步的方式完成,TPS是支撑不了多长时间的

但是在12306里面的模型是

下单-》 减库存和订单同时异步进行 -》 等待付款

异步是当你下完订单之后,它一个线程去减库存,另外一个线程直接把你下单的信息扔到kafka或者redis里面直接返回OK,你下单成功后等待你付款,什么时候你付款完成后面那些个订单处理线程就会去里面拿数据,这个处理完了就会持久化到Hbase或者是mysql,一般大流量的处理方法核心思想就是:分而治之

JVM优化

比如我有一个50万PV的资料类网站(从磁盘提取文档到内存)原服务器32位,1.5G的堆,用户反馈网站比较缓慢,如果对它进行升级,新服务器64位,16G的堆内存,用户还是反馈卡顿,而且还比之前更严重,这个是因为什么呢?一般来说很多用户去浏览数据,很多数据会load到内存中,导致内存不足,频繁的GC,STW时间过长,响应时间就会变慢,那我们应该怎么办呢,使用 PS-> PN+CMS或者G1。

还有一个就是系统CPU经常100%,我们要如何进行调优呢?

首先我们可以想到CPU100%那么一定有线程在占用系统资源

1.找出哪个进程CPU高 (top命令)

2.该进程中的哪个线程CPU高(top -Hp)

3.导出该线程的堆栈

4.查找哪个方法(栈挣)比较消耗时间

5.工作线程占比高 | 垃圾回收线程占比高

总结

今天我们只是讲解了一些基本的操作,具体怎么操作该怎么办呢?这一部分小农会在下一部分中进行讲解,今天主要带大家了解一些常用的参数,告诉大家怎么去使用和一些前置知识。

到此这篇关于java虚拟机之JVM调优详解的文章就介绍到这了,更多相关JVM调优详解内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 浅析Java虚拟机详解之概述、对象生存法则

    Java与C++之间有一堵由内存分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来. 一.概述 Java堆和方法区这两个区域有着很显著的不确定性: 1.一个接口的多个实现类需要的内存可能会不一样,一个方法所执行的不同条件分支所需要的内存也可能不一样 2.只有处于运行期间,我们才能知道程序究竟会创建哪些对象,创建多少个对象,这部分内存的分配和回收是动态的 垃圾收集器所关注的正是这部分的内存该如何管理 二.对象已死? 1.引用计数法 在对象中添加一个引用计数器,每当有一个地方引用它

  • Java虚拟机执行引擎知识总结

    执行引擎 也只有几个概念, JVM方法调用和执行的基础数据结构是 栈帧, 是内存区域中 虚拟机栈中的栈元素, 每一个方法的执行就对应着一个栈帧在虚拟机栈中出栈入栈的过程. 栈帧:则是包含有局部变量表, 操作数栈, 动态连接, 方法返回地址, 附加信息. 1 局部变量表: 存储单位是 slot, 一个slot占据32位, 对于64位的数据类型, 则是分配连续两个slot空间. 而对于一个非静态方法而言, 有一个隐藏参数, 为 this, 而在局部变量表中的变量存储顺序则是 this -> 方法参数

  • Java基础之创建虚拟机对象的过程详细总结

    一.对象的创建 1.1 new 类名 虚拟机遇到一条new指令时,首先检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并检查这个符号引用代表的类是否已经被加载.解析和初始化过.如果没有,先执行相应的类加载过程. 1.2 分配内存 虚拟机为新生对象分配内存.对象所需内存大小在类加载完成后就可以确定,为对象分配内存等同于把一块确定大小的内存从Java堆中划分出来. (1)内存分配的方式有两种: ① 指针碰撞: java堆如果规整,一边是用过的内存,一边是空闲的内存,中间一个指针作为边界指示

  • Java虚拟机内存溢出与内存泄漏

    一.基本概念 内存溢出:简单地说内存溢出就是指程序运行过程中申请的内存大于系统能够提供的内存,导致无法申请到足够的内存,于是就发生了内存溢出. 内存泄漏:内存泄漏指程序运行过程中分配内存给临时变量,用完之后却没有被GC回收,始终占用着内存,既不能被使用也不能分配给其他程序,于是就发生了内存泄漏. 内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory: 内存泄露 memory leak,是指程序在申请内存后,无法释放已申请的内存空间

  • java虚拟机jvm方法区实例讲解

    和java堆一样,方法区是一块所有线程共享的内存区域,用于保存系统的类信息,类的信息有哪些呢.字段.方法.常量池.方法区也有一块内存区域所以方法区的内存大小,决定了系统可以包含多少个类,如果系统类太多,方法区内存不够肯定会导致方法区溢出,虚拟机同样会抛出内存溢出信息.(内存溢出后面相关文章给大家总结) jdk6和jdk7中,方法区可以理解为永久区(Perm).永久区可以使用参数-XX:PermSize和-XX:MaxPermSize制定.默认情况下-XX:MaxPermSize为64MB.如果你

  • Java启用Azure Linux虚拟机诊断设置

    在官方的这篇文档中为大家介绍了如何使用Java开启Azure Windows虚拟机的诊断设置 这篇文章呢,为大家介绍一下如何使用Java开启Linux的诊断日志. 其实实现思路大体都是相同的,都是使用rest api开启,不过需要注意的是请求体不同,Linux和Windows使用的插件完全不一样,请求体的配置也有很大的区别,Linux的诊断扩展的请求体可以参考此文档 需要注意的是受保护设置这一节的配置,Windows中该节允许直接配置存储账户的Key,但是Linux是不支持的,Linux只支持S

  • java虚拟机是做什么用的

    为了能够在不同的平台支持java的语言,我们需要一种辅助机制进行翻译,所以java虚拟机就诞生了,也就是平时所说的JVM.能够对java语言进行翻译,然后适应于其他的平台.下面窝们就JVM的概念,与其他机制的关系.设置参数带来介绍,然后讲解其中的一个重点知识点. 1.概念 JVM是java上的一个虚构出来的计算机,是一个位于Java与操作系统之间的中间态.有自己完善的硬件结构,如处理器.堆栈.寄存器等,还具有相应的指令系统. 2.JVM.JRE和JDK的关系 3.设置JVM内存的参数有四个 -X

  • Java虚拟机常见内存溢出错误汇总

    一.引言 从事java开发的小伙伴在平时的开发工作中,应该会遇见各式各样的异常和错误,在实际工作中积累的异常或者错误越多,趟过的坑越多,就会使我们编码更加的健壮,就会本能地避开很多严重的坑.以下介绍几个Java虚拟机常见内存溢出错误.以此警示,避免生产血案. 二.模拟Java虚拟机常见内存溢出错误 1.内存溢出之栈溢出错误 package com.jayway.oom; /** * 栈溢出错误 * 虚拟机参数:-Xms10m -Xmx10m * 抛出异常:Exception in thread

  • Java内存模型中的虚拟机栈原理分析

    Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域,这些区域都会有各自的用途,以及创建和销毁的时间,有的区域会随着虚拟机进程的启动而存在,有些区域则依赖用户线程的启动和结束而建立和销毁.Java虚拟机所管理的内存将会包括以下几个运行时数据区域.如下图所示(图片来自<深入理解Java虚拟机>一书). 在内存中,栈分为两部分,一部分是本地方法栈,为虚拟机使用到的Native方法服务,具体的虚拟机可以自由实现,另一部分就是虚拟机栈,主要是为虚拟机执行Java方法服务

  • java虚拟机创建失败的原因整理

    创建java虚拟机失败的解决方法 解决问题的步骤: 1.从eclipse文件夹中打开eclipse.ini文件 2.修改–launcher.XXMaxPermSize属性 3.将值改为512m即可 配置文件格式: -startup plugins/org.eclipse.equinox.launcher_1.3.0.v20120522-1813.jar --launcher.library plugins/org.eclipse.equinox.launcher.win32.win32.x86_

  • Java虚拟机之类加载

    一.类加载流程 类加载的流程可以简单分为三步: 加载 连接 初始化 而其中的连接又可以细分为三步: 验证 准备 解析 下面会分别对各个流程进行介绍. 1.1 类加载条件 在了解类接在流程之前,先来看一下触发类加载的条件. JVM不会无条件加载类,只有在一个类或接口在初次使用的时候,必须进行初始化.这里的使用是指主动使用,主动使用包括如下情况: 创建一个类的实例的时候:比如使用new创建,或者使用反射.克隆.反序列化 调用类的静态方法的时候:比如使用invokestatic指令 使用类或接口的静态

  • Java虚拟机使用jvisualvm工具远程监控tomcat内存

    jdk中自带了很多工具可以用于性能分析,位于jdk的bin目录下,jvisualvm工具可以以图形化的方式更加直观的监控本地以及远程的java进程的内存占用,线程状态等信息. 一.配置tomcat 在tomcat的catalina.sh文件开头加上如下配置: JAVA_OPTS="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9999 -Dcom.sun.management.jmxremote.ssl=fa

  • 深入了解Java虚拟机栈以及内存模型

    1.结合字节码指令理解Java虚拟机栈和栈帧 栈帧:每个栈帧对应一个被调用的方法,可以理解为一个方法的运行空间. 每个栈帧中包括局部变量表(Local Variables).操作数栈(Operand Stack).指向运行时常量池的引用(A reference to the run-time constant pool).方法返回地址(Return Address)和附加信息. 局部变量表:方法中定义的局部变量以及方法的参数存放在这张表中,局部变量表中的变量不可直接使用,如需要使用的话,必须通过

  • java虚拟机钩子关闭函数addShutdownHook的操作

    当jvm虚拟机被关闭的时候,可能我们需要做一些处理,比如对连接的关闭,或者对一些必要信息的存储等等操作,这里就可以借助于虚拟机提供的钩子函数,当jvm虚拟机关闭之前会去调用addShutdownHook注册的线程钩子. 这里做一个小实验,项目结构如下: 1.自定义的ApplicationContext的上下文 package cn.lijie; public class ApplicationContext { private static ApplicationContext applicat

  • 详解Java 虚拟机垃圾收集机制

    1 垃圾收集发生的区域 之前我们介绍过 Java 内存运行时区域的各个部分,其中程序计数器.虚拟机栈.本地方法栈三个区域随线程共存亡.栈中的每一个栈帧分配多少内存基本上在类结构确定下来时就已知,因此这几个区域的内存分配和回收都具有确定性,不需要考虑如何回收的问题,当方法结束或线程结束,内存自然也跟着回收了 而 Java 堆和方法区这两个区域则有显著的不确定性,只有在程序运行时我们才能知道程序究竟创建了哪些对象,创建了多少对象,所以这部分内存的分配和回收是动态的,垃圾收集器所关注的正是这部分内存该

  • 概述java虚拟机中类的加载器及类加载过程

    1. 类加载子系统 1.1 概述 类加载子系统负责从文件系统或者网络中加载Class文件,Class文件在文件开头有特定的文件标识 ClassLoader只负责class文件的加载,至于它是否可以运行,则由Execution Engine 决定 加载的类信息存放于一块成为 :方法区的内存空间,除了类的信息外,方法区中还会存放运行时常量池信息,可能还包括字符串字面量和数字常量(这部分常量信息是Class文件中常量池部分的内存映射) 字节码中的常量池加载到 方法区 -----> 运行时常量池信息 1

  • Java虚拟机内存区域划分详解

    在谈 JVM 内存区域划分之前,我们先来看一下 Java 程序的具体执行过程,我画了一幅图. Java 源代码文件经过编译器编译后生成字节码文件,然后交给 JVM 的类加载器,加载完毕后,交给执行引擎执行.在整个执行的过程中,JVM 会用一块空间来存储程序执行期间需要用到的数据,这块空间一般被称为运行时数据区,也就是常说的 JVM 内存. 所以,当我们在谈 JVM 内存区域划分的时候,其实谈的就是这块空间--运行时数据区. 大家应该对官方出品的<Java 虚拟机规范>有所了解吧?了解这个规范可

  • Java跨平台原理与虚拟机相关简介

    Java跨平台原理(字节码文件.虚拟机) C/C++语言都直接编译成针对特定平台机器码.如果要跨平台,需要使用相应的编译器重新编译. Java源程序(.java)要先编译成与平台无关的字节码文件(.class),然后字节码文件再解释成机器码运行.解释是通过Java虚拟机来执行的. 字节码文件不面向任何具体平台,只面向虚拟机. Java虚拟机是可运行Java字节码文件的虚拟计算机.不同平台的虚拟机是不同的,但它们都提供了相同的接口. Java语言具有一次编译,到处运行的特点.就是说编译后的.cla

随机推荐