性能优化系列三:JVM优化1

一、几个基本概念

GCRoots对象都有哪些

所有正在运行的线程的栈上的引用变量。所有的全局变量。所有ClassLoader。。。

1.System Class
.2.JNI Local
3.JNI Global
4.Thread Block
5.Busy Monitor
6.Java Local
7.Native Stack
8.Unfinalized
9.Unreachable
10.Java Stack Frame
11.Unknown

栈帧的解释

Java虚拟机栈(Java Virtual Machine Stacks)是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

简单地说,栈帧就是一个方法,里面有输入输出参数,局部变量表,返回值等信息,第一个参数一定是this

方法区说明

与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

举例:有一个HelloWorld的类如下

import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.log4j.Logger;
public class HelloWorld {
private static Logger LOGGER = Logger.getLogger(HelloWorld.class.getName());
public void sayHello(String message) {
SimpleDateFormat formatter = new SimpleDateFormat("dd.MM.YYYY");
String today = formatter.format(new Date());
LOGGER.info(today + ": " + message);
}
}

堆区、方法区、栈区存放的东西如下:

说明:堆区存放的是对象信息,方法区存放的是类信息、常量、静态变量、即时编译后的代码等数据;栈区存放的是线程、参数、变量、行号

二、JIT优化

JIT优化指的是即时编译器优化(Just In Time)

常规优化

1、禁用System.gc

因为System.gc会触发full GC,非常耗系统性能,所以要禁用

参数设置

-XX:-DisableExplicitGC,禁用了System.gc()的显示调用

2、逃逸分析与标量替换

分析对象动态作用域:当一个对象在方法中被定义后,它可能被外部方法所引用,例如作为调用参数传递到其他方法中,称为方法逃逸。 甚至还有可能被外部线程访问到,譬如赋值给类变量或可以在其他线程中访问的实例变量,称为线程逃逸。
栈上分配(Stack Allocation):如果确定一个对象不会逃逸出方法之外,那让这个对象在栈上分配内存将会是一个很不错的主意。由于HotSpot虚拟机目前的实现方式导致栈上分配实现起来比较复杂,因此在HotSpot中暂时还没有做这项优化。
同步消除(Synchronization Elimination):线程同步本身是一个相对耗时的过程,如果逃逸分析能够确定一个变量不会逃逸出线程,无法被其他线程访问,那这个变量的读写肯定就不会有竞争,对这个变量实施的同步措施也就可以消除掉。
标量替换(Scalar Replacement):标量(Scalar)是指一个数据已经无法再分解成更小的数据来表示了,Java虚拟机中的原始数据类型(int、 long等数值类型以及reference类型等)都不能再进一步分解,它们就可以称为标量。 相对的,如果一个数据可以继续分解,那它就称作聚合量(Aggregate),Java中的对象就是最典型的聚合量。 如果把一个Java对象拆散,根据程序访问的情况,将其使用到的成员变量恢复原始类型来访问就叫做标量替换。 如果逃逸分析证明一个对象不会被外部访问,并且这个对象可以被拆散的话,那程序真正执行的时候将可能不创建这个对象,而改为直接创建它的若干个被这个方法使用到的成员变量来代替。

标量替换的示例:

有一个类A
public class A{

     public int a=1;
     public int b=2

} 

方法getAB使用类A里面的a,b
private void getAB(){

     A x = new A();
     x.a;
     x.b;

}

JVM在编译的时候会直接编译成
private void getAB(){

     a = 1;
     b = 2;

}
这就是标量替换

参数设置:

逃逸分析默认是启用的,-XX:+DoEscapeAnalysis。后续有三种优化会进行:栈内分配,同步消除,标量替换

3、关闭偏向锁优化

偏向锁的概念:一把锁被使用之后不主动释放,保留给当前的使用者,预判等下一个进程来获取的时候再释放出来,

参数设置:

偏向锁关闭: -XX:-UseBiasedLocking

-XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0

4、指针压缩

参数设置:

-XX:+UseCompressedOops

5、getter方法优化

指内联函数的优化,何为内联函数呢,即一个方法里面调用了另外一个方法,JVM在编译的时候把被调用的方法合入到调用的方法里面,这样就能减少栈帧的创建(因为每一个方法执行时都会创建一个栈帧),节约内存

使用示例:

方法1:
private void getA(){

    getB()

}

方法2:
private void getB(){

    system.out.print("getB");

}

如果配置了getter方法的优化参数,JVM在编译的时候会编译成如下形式

private void getA(){

    system.out.print("getB");

}

参数设置:

getter方法优化,-XX:UseFastAccessorMethods

JIT优化

1、开启服务端模式

开启服务端模式以后就有即时编译器和解释器两种执行引擎,执行效率最高的是即时编译器,所以我们做JIT优化的目的是尽量使代码使用即时编译器

参数设置:

-server

2、增加内联函数的可能性

增加函数内联的可能性能减少栈帧的创建,节约内存空间

参数设置:

使用final修饰函数向编译器建议可以内联,启动参数不宜设置,注意只是建议,具体是否内联看JVM决定

3、提高使用即时编译器的可能性

小方法:写方法时尽量不要写得太大,让JVM尽可能使用即时编译器编译代码

在启动项配置参数-XX:CompileThreshold=10000,使得一个方法被调用超过10000次以后使用即时编译器编译为机器码

OSR编译阈值

A、调用计数器,即方法被调用的次数,CompileThreshold,该值是指当方法被调用多少次后,就编译为机器码,client模式默认为1500次,server模式默认为1万次,可以在启动时添加-XX:CompileThreshold=10000来设置该值。
B、回边计数器,即方法中循环执行部分代码的执行次数,OnStackReplacePercentage,该值用于/参与计算是否触发OSR编译的阈值,client默认为933,sever默认为140,可以通过-XX:OnStackReplacePercentage=140来设置。
client模式下的计算规则为
CompileThreshold*OnStackReplacePercentage/100,
server模式下计算规则为
CompileThreshold*(OnStackReplacePercentage-InterpreterProfilePercentage)/100。
InterpreterProfilePercentage,默认为33。

4、降低线程优先级

Linux不能设置,需要root权限

5、热度衰减与半衰周期

三、内存优化

1、将新对象预留在年轻代

参数设置:

-XX:TargetSurvivorRatio=90

90表示让新生代的from区的利用率为90%,这样新对象进来就会优先在里面

2、让大对象进入年老代

参数设置:

-XX:PetenureSizeThreshold=1000000,1M

大小为1M的对象为大对象

3、设置对象进入年老代的年龄

参数设置:

-XX:MaxTenuringThreshold=31

表示在新生代经过31次回收以后还存活的对象移到老年代,默认值是15,设置31的目的是让对象尽可能的在新生代就被回收,避免进入老年代触发full GC

4、稳定的 Java 堆

参数设置:

Xmx与Xms相同

最小堆内存和最大堆内存设置为一样的目的是避免频繁的向操作系统申请内存占用系统资源

5、增大吞吐量提升系统性能

指设置合理的垃圾回收器

参数设置:

– X X : + U s e P a r a l l e l G C :年轻代使用多线程的收集器

–XX:+UseParallelOldGC:老年代使用多线程的垃圾收集器

–XX:ParallelGC-Threads(CPU核心数相等):设置垃圾回收时使用的线程数

6、使用非占有的垃圾回收器

参数设置:

–XX:+UseConcMarkSweepGC:使用CMS垃圾回收器

四、监控及工具

1.  jps:虚拟机进程状况工具

它的功能也和ps命令类似:可以列出正在运行的虚拟机进程,并显示虚拟机执行主类(Main Class,main()函数所在的类)名称以及这些进程的本地虚拟机唯一ID(Local Virtual Machine Identifier,LVMID)。
jps可以通过RMI协议查询开启了RMI服务的远程虚拟机进程状态,hostid为RMI注册表中注册的主机名。

简单地说:jps可以用来查看java进程的id

参数选项:

2. jstat:虚拟机统计信息监视工具

用于监视虚拟机各种运行状态信息的命令行工具。它可以显示本地或者远程虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据,在没有GUI图形界面,只提供了纯文本控制台环境的服务器上,它将是运行期定位虚拟机性能问题的首选工具

参数选项:

3. jmap:Java内存映像工具

jmap的作用并不仅仅是为了获取dump文件,它还可以查询finalize执行队列、Java堆和永久代的详细信息,如空间使用率、当前用的是哪种收集器等。

参数选项:

4. 其他工具

jinfo:Java配置信息工具
作用是实时地查看和调整虚拟机各项参数。使用-sysprops选项把虚拟机进程System.getProperties()的内容打印出来。
jhat:虚拟机堆转储快照分析工具,和jmap配合使用
jhat内置了一个微型的HTTP/HTML服务器,jmap生成dump文件的分析结果后,可以在浏览器中查看。
HSDIS:JIT生成代码反汇编
HSDIS是一个HotSpot虚拟机JIT编译代码的反汇编插件,它包含在HotSpot虚拟机的源码之中,但没有提供编译后的程序。

5. 可视化工具

JConsole:Java监视与管理控制台
JConsole(Java Monitoring and Management Console)是一种基于JMX的可视化监视、管理工具。它管理部分的功能是针对JMX MBean进行管理,由于MBean可以使用代码、中间件服务器的管理控制台或者所有符合JMX规范的软件进行访问。

VisualVM:多合一故障处理工具
VisualVM(All-in-One Java Troubleshooting Tool)是到目前为止随JDK发布的功能最强大的运行监视和故障处理程序。VisualVM的还有一个很大的优点:不需要被监视的程序基于特殊Agent运行,因此它对应用程序的实际性能的影响很小,使得它可以直接应用在生产环境

JMC,Oracle Java Mission Control 是一个用于对 Java 应用程序进行管理、监视、概要分析和故障排除的工具套件。首次安装时,Java Mission Control 包括 JMX 控制台和 Java 飞行记录器。从 Mission Control 中可以轻松安装更多插件

6. 即时编译器监控工具JITWatch

安装:
git clone [email protected]:AdoptOpenJDK/jitwatch.git
cd jitwatch
mvn clean install -DskipTests=true
运行:launchUI.bat
使用:XX:+UnlockDiagnosticVMOptions -XX:+TraceClassLoading -XX:+LogCompilation - XX:+PrintAssembly
查看结果。

五、JVM优化配置示例

服务器:8 cpu, 8G mem
e.g.
java -Xmx3550m -Xms3550m -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxPermSize=16m -XX:MaxTenuringThreshold=0
调优方案:
-Xmx5g:设置JVM最大可用内存为5G。
-Xms5g:设置JVM初始内存为5G。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。
-Xmn2g:设置年轻代大小为2G。整个堆内存大小 = 年轻代大小 + 年老代大小 + 持久代大小 。持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。
-XX:+UseParNewGC:设置年轻代为并行收集。可与CMS收集同时使用。JDK5.0以上,JVM会根据系统配置自行设置,所以无需再设置此值。
-XX:ParallelGCThreads=8:配置并行收集器的线程数,即:同时多少个线程一起进行垃圾回收。此值最好配置与处理器数目相等。
-XX:SurvivorRatio=6:设置年轻代中Eden区与Survivor区的大小比值。根据经验设置为6,则两个Survivor区与一个Eden区的比值为2:6,一个Survivor区占整个年轻代的1/8。
-XX:MaxTenuringThreshold=30: 设置垃圾最大年龄(次数)。如果设置为0的话,则年轻代对象不经过Survivor区直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概率。设置为30表示 一个对象如果在Survivor空间移动30次还没有被回收就放入年老代。
-XX:+UseConcMarkSweepGC:设置年老代为并发收集。测试配置这个参数以后,参数-XX:NewRatio=4就失效了,所以,此时年轻代大小最好用-Xmn设置,因此这个参数不建议使用

原文地址:https://www.cnblogs.com/leeSmall/p/9325164.html

时间: 2024-11-05 16:31:37

性能优化系列三:JVM优化1的相关文章

[转]JVM系列三:JVM参数设置、分析

[转]JVM系列三:JVM参数设置.分析 不管是YGC还是Full GC,GC过程中都会对导致程序运行中中断,正确的选择不同的GC策略,调整JVM.GC的参数,可以极大的减少由于GC工作,而导致的程序运行中断方面的问题,进而适当的提高Java程序的工作效率.但是调整GC是以个极为复杂的过程,由于各个程序具备不同的特点,如:web和GUI程序就有很大区别(Web可以适当的停顿,但GUI停顿是客户无法接受的),而且由于跑在各个机器上的配置不同(主要cup个数,内存不同),所以使用的GC种类也会不同(

Mysql优化系列之数据类型优化

本篇是优化系列的第一篇:数据类型 为了不产生赘述,尽量用简洁的语言来描述. 在选择数据类型之前,首先要知道几个原则: 更小的通常更好 尽量使用可以正确存储数据的最小数据类型.更小的数据类型意味着更快,占用更少的磁盘,内存以及缓存,以及处理时间 简单就好 这是出于操作数据类型的效率和代价考虑.整型比字符型操作代价更低,因为字符集和校对规则是字符处理比整型更复杂 两个例子:使用Mysql内建的datatime而不是字符串存储时间,使用整型而不是IP字符串存IP地址 尽量避免NULL 这是个很烦人的值

Android性能优化系列之渲染优化

众所周知的Android系统每隔16ms重新绘制一次activity,也就是说你的app必须在16ms内完成屏幕刷新的所有逻辑操作,这样才能达到60帧/s.而用户一般所看到的卡顿是由于Android的渲染性能造成的. 本篇博客将介绍Android的渲染相关知识. 然而有的时候你的程序会出现这样的情况,如果某个绘制操作超过了16秒用了24秒这时候用户看同一张图片花了32秒而不是16s,用户会感到卡顿,这种现象我们叫-丢帧 Android的渲染机制 首先我们要了解android的渲染机制,andro

PLSQL_性能优化系列04_Oracle Optimizer优化器

2014-09-25 BaoXinjian 一.摘要 1. Oracle优化器介绍 本文讲述了Oracle优化器的概念.工作原理和使用方法,兼顾了Oracle8i.9i以及最新的10g三个版本.理解本文将有助于您更好的更有效的进行SQL优化工作. 2. RBO优化器 RBO是一种基于规则的优化器,随着CBO优化器的逐步发展和完善,在最新的10g版本中Oracle已经彻底废除了RBO. 正在使用Oracle8i或9i的人们或多或少的都会碰到RBO,因此在详细介绍CBO之前,我们有必要简单回顾一下古

APP性能优化系列:内存优化-bitmap详解

??在Android应用开发中,我们经常需要跟图片打交道,而图片一个很麻烦的问题是占用内存非常大,经常导致OOM,了解Bitmap相关信息,不同sdk版本中Android图片处理的变化,以及一些优化处理的方式对我们平时开发中对图片的会非常有帮助. ??在开始本节的内容之前我们.先来区分几个名词的概念: Drawable:通用的图形对象,用于装载常用格式的图像,既可以是PNG,JPG这样的图像, 也是前面学的那13种Drawable类型的可视化对象!我们可以理解成一个用来放画的--画框! Bitm

Unity3D静态对象优化系列三

我们接着系列二的问题继续讲解,系列二中的问题是如果多个材质是相同的,它没有去优化,接下来我们将其优化一下,首先要找到在哪里去优化,我们看下面的for循环语句也是系列二的代码,如下:                 for (int s = 0; s < meshFilter.sharedMesh.subMeshCount; s++)                 {                     int materialArrayIndex = 0;                 

SQL语句优化系列三(关于select查询)

关于select查询 输出表中的所有列   select  *  from 表名 输出表中的部分列   select  字段名表 from 表名 为结果集内的列指定列名  select  {字段名1 [ as 列的别名]  [,-n]}  from 表名 消除取值重复的行,在select 后面紧跟 distinct 限制返回的行数    select  top 行数 列名表 from 表名 查询满足条件的元组  select  *  from 表名 where 查询条件 比较:列表达式1 比较运

JVM系列三:JVM参数设置、分析

转:http://www.cnblogs.com/redcreen/archive/2011/05/04/2037057.html 不管是YGC还是Full GC,GC过程中都会对导致程序运行中中断,正确的选择不同的GC策略,调整JVM.GC的参数,可以极大的减少由于GC工作,而导致的程序运行中断方面的问题,进而适当的提高Java程序的工作效率.但是调整GC是以个极为复杂的过程,由于各个程序具备不同的特点,如:web和GUI程序就有很大区别(Web可以适当的停顿,但GUI停顿是客户无法接受的),

(转)JVM系列三:JVM参数设置、分析

不管是YGC还是Full GC,GC过程中都会对导致程序运行中中断,正确的选择不同的GC策略,调整JVM.GC的参数,可以极大的减少由于GC工作,而导致的程序运行中断方面的问题,进而适当的提高Java程序的工作效率.但是调整GC是以个极为复杂的过程,由于各个程序具备不同的特点,如:web和GUI程序就有很大区别(Web可以适当的停顿,但GUI停顿是客户无法接受的),而且由于跑在各个机器上的配置不同(主要cup个数,内存不同),所以使用的GC种类也会不同(如何选择见GC种类及如何选择).本文将注重