Java性能权威指南读书笔记--之一
JIT(即时编译)
解释型代码:程序可移植,相同的代码在任何有适当解释器的机器上,都能运行,但是速度慢。
编译型代码:速度快,电视不同CPU平台的代码无法兼容。
java则是使用java的编译器先将其编译为class文件,也就是字节码;然后将字节码交由jvm(java虚拟机)解释执行。由于这个编译是在程序执行时进行的,因此被称为“即使编译”。
热点编译
对于程序来说,通常只有一部分代码被经常执行,而应用的性能就取决于这些代码执行得有多快。这些关键代码段被称为应用的热点,代码执行得越多就被认为是越热。
因此JVM执行代码时,并不会立即编译代码:
- 如果代码只执行一次,那编译完全就是浪费精力。对于只执行一次的代码,解释执行Java字节码比先编译然后执行的速度快。
- JVM执行特定方法或者循环的次数越多,它就会越了解这段代码。这使得JVM可以在编译代码时进行大量优化。
分层编译
Client编译器和server编译器主要的区别在于编译代码的时机不同。client编译器开启编译比server编译器要早。这意味着在代码执行的开始阶段,client编译器比server编译器要快,因为它的编译代码相比server编译器而言要多。
分层编译是综合了client和server的优点。在开启分层编译(-XX:+TieredCompilation)后代码先由client编译器编译,随着代码变热,由server编译器重新编译。
调优代码缓存
JVM编译代码时,会在代码缓存中保留编译之后的汇编语言指令集。代码缓存的大小固定,所以一旦填满,JVM就不能编译更多代码了。
也就是说,如果代码缓存过小,那么就会有一些热点代码被编译了,而其他没有,最终导致应用的大部分代码都是解释运行(非常慢)。这个问题在使用client编译器或进行分层编译时很常见。
当代码缓存填满时,JVM通常会发出以下警告:
Java HotSopt(TM) 64-Bit Server VM warning:CodeCache is full.Compiler has bean disabled.
Java HotSopt(TM) 64-Bit Server VM warning:Try increasing the code cache size using -XX:ReservedCodeCacheSize=
各平台代码缓存的默认大小:
| jvm | jdk版本 | 大小 |
|---|---|---|
| 32位client | Java8 | 32MB |
| 32位client | 分层编译,Java8 | 240MB |
| 64位client | 分层编译,Java8 | 240MB |
| 32位client | Java7 | 32MB |
| 32位server | Java7 | 32MB |
| 64位server | Java7 | 48MB |
| 64位server | 分层编译,Java7 | 48MB |
如果代码缓存设为1GB,JVM就会保留1GB的本地内存空间。如果是32位JVM,那么进程占用的总内存不能超过4GB(包括Java堆、JVM自身所有代码占用空间、分配给应用的本地内存、代码缓存)。
通过jconsole Memory(内存)面板的Memory Pool Code Cache图表,可以监控代码缓存。
编译阈值
一旦代码执行到一定次数,且达到了编译阈值,编译器就可以获得足够的信息编译代码了。
编译是基于两种JVM计数器的:方法调用计数器和方法中的循环回边计数器。回边实际上可以看作是循环完成执行的次数。
栈上替换:JVM可以在方法循环运行时进行编译,并在循环代码编译结束之后,JVM替换还在栈上的代码,循环的下一次迭代就会执行快的多的代码。
标准编译由-XX:CompileThreshold=N标志触发。使用client编译器时,N的默认值是1500,使用server编译器时为10000。
计数器会随着时间而减少,所以计数器只是方法或循环最新热度的度量。由此带来一个副作用是,执行不太频繁的代码可能永远不会编译。
检测编译过程
-XX:+PrintCompilation
如果开启PrintCompilation,每次编译一个方法(或循环)时,JVM就会打印一行被编译的内容信息。
绝大多数编译日志的行具有以下格式:
timestamp compilation_id attributes (tiered_level) method_name size deopt
timestamp表示编译完成的时间
compilation_id内部的任务ID
attributes是一组5个字符长的串,表示代码编译的状态。如果给定的编译被赋予了特定属性,就会打印下面列表中所显示的字符,否则该属性就打印一个空格。
* % :编译为OSR
* s :方法是同步的
* !:方法有异常处理器
* b :阻塞模式时发生的编译
* n:为封装本地方法所发生的编译
tiered_level 如果程序没有使用分成编译的方式运行则为空,否则为数字,表明所完成编译的级别
method_name格式为:ClassName::method
然后是编译后代码大小(单位是字节)
最后,在某些情况下,编译日志的结尾会有一条信息,表明发生了某种逆优化,通常是“made not entrant”或”made zombie”
135 1 n 0 java.lang.Thread::currentThread (native) (static)
136 2 3 java.util.Arrays::copyOf (19 bytes)
136 7 3 sun.nio.cs.UTF_8$Encoder::encode (359 bytes)
137 8 2 java.lang.String::hashCode (55 bytes)
使用jstat -compiler 进程ID 也可以看有多少方法被编译
使用jstat -printcompilation 5003 1000 表示进程ID为5003的程序每1秒输出一次最近被编译的方法
编译器线程
当方法(或循环)适合编译时,就会进入到编译队列。队列则由一个或多个后台线程处理。编译队列是一种优先队列,即调用计数次数多的方法有更高的优先级。
当开启分层编译时,JVM默认开启多个client和server线程。
| cpu数量 | C1的线程数(client) | C2的线程数(server) |
|---|---|---|
| 1 | 1 | 1 |
| 2 | 1 | 1 |
| 4 | 1 | 2 |
| 8 | 1 | 2 |
| 16 | 2 | 6 |
| 32 | 3 | 7 |
| 64 | 4 | 8 |
| 128 | 4 | 10 |
编译器的线程数可通过-XX:CICompilerCount=N标志来设置。对于分层编译来说,设置的值中三分之一将用来处理client编译器队列,其余的线程(至少一个)用来处理server编译器队列。
使用分层编译时,线程数很容易超过系统限制,特别是有多个JVM同时运行的时候。在这种情况下,减少线程数有助于提高整体的吞吐量(尽管代价可能是热身期会持续得更长)。
方法内联
public class Point{
private int x,y;
public int getX(){ return x; }
public void setX(int i){ x = i;}
}
如果你写下面的代码
Point p = getPoint();
p.setX(p.getX()*2);
编译后的代码本质上执行的是:
Point p = getPoint();
p.x = p.x *2;
方法是否内联取决于它有多热以及它的大小。
-XX:MaxInlineSize=N默认是35字节,即只有方法小于35字节时第一次调用方法时就会被内联。
-XX:MaxFreqInlineSize=N默认是325字节,即只有当一个方法频繁被调用并且小于325字节时会被内联。
逃逸分析
-XX:+DoEscapeAnalysis默认为true。逃逸分析可以让JVM对一个对象根据代码来进行优化。
- 栈上分配
我们都知道Java中的对象都是在堆上分配的,而垃圾回收机制会回收堆中不再使用的对象,但是筛选可回收对象,回收对象还有整理内存都需要消耗时间。如果能够通过逃逸分析确定某些对象不会逃出方法之外,那就可以让这个对象在栈上分配内存,这样该对象所占用的内存空间就可以随栈帧出栈而销毁,就减轻了垃圾回收的压力。 - 同步消除
如果发现某个对象只能从一个线程可访问,那么在这个对象上的操作可以不需要同步。 - 标量替换
Java虚拟机中的原始数据类型(int,long等数值类型以及reference类型等)都不能再进一步分解,它们就可以称为标量。相对的,如果一个数据可以继续分解,那它称为聚合量,Java中最典型的聚合量是对象。如果逃逸分析证明一个对象不会被外部访问,并且这个对象是可分解的,那程序真正执行的时候将可能不创建这个对象,而改为直接创建它的若干个被这个方法使用到的成员变量来代替。拆散后的变量便可以被单独分析与优化,可以各自分别在栈帧或寄存器上分配空间,原本的对象就无需整体分配空间了。
小结
- 不用担心小方法,特别是getter和setter,因为它们容易内联。
- 需要编译的代码在编译队列中,队列中代码越多,程序打到最佳性能的时间越久。
- 虽然代码缓存的大小可以调整,但它仍然是有限的资源
- 代码越简单,优化越多。
Java性能权威指南读书笔记--之一的更多相关文章
- Java性能权威指南读书笔记--之二
新生代填满时,垃圾收集器会暂停所有的应用线程,回收新生代空间.这种操作被称为Minor GC. 老年代被填满时,垃圾收集器会暂停所有应用线程,对其进行回收,接着对堆空间进行整理.这个过程被称为Full ...
- 经典的性能优化最佳实践 web性能权威指南 读书笔记
web性能权威指南 page 203 经典的性能优化最佳实践 无论什么网络,也不管所用网络协议是什么版本,所有应用都应该致力于消除或减 少不必要的网络延迟,将需要传输的数据压缩至最少.这两条标准是经典 ...
- 《Java性能权威指南》笔记----JIT编译器
概览 编译型语言(C++,Fortran等):运行程序前,需要用编译器将代码静态编译成CPU可执行的汇编码.汇编码针对特定的CPU. 优点:只需编译一次,且有足够的程序信息来优化汇编码.执行速度快: ...
- 《Java性能权威指南》笔记----Java性能调优工具
OS 1.CPU 用户态时间(us):cpu执行应用代码所占时间的百分比. 内核态时间(sy):cpu执行内核代码所占时间的百分比,系统态时间与应用相关. 空闲时间(id):cpu空闲时间百分比.空闲 ...
- HTTP权威指南读书笔记
HTTP权威指南笔记 读书有两种境界,第一种境界是将书读薄,另一种是读厚.本篇文章就是HTTP权威指南的读书笔记,算是读书的第一重境界,将厚书读薄.文章对HTTP的一些关键概念做了比较详细的概述,通读 ...
- css权威指南读书笔记
今天翻手机,翻到了许久之前看css权威指南时的笔记,遂移到博客中来. 1.属性选择器p.one class名为one的p元素p[class][name] 含有class和name属性的p元素p[cla ...
- css权威指南读书笔记-第10章浮动和定位
这一章看了之后真是豁然开朗,之前虽然写了圣杯布局和双飞翼布局,有些地方也是模糊的,现在打算总结之后再写一遍. 以下都是从<css权威指南>中摘抄的我认为很有用的说明. 浮动元素 一个元素浮 ...
- Java性能优化权威指南-读书笔记(五)-JVM性能调优-吞吐量
吞吐量是指,应用程序的TPS: 每秒多少次事务,QPS: 每秒多少次查询等性能指标. 吞吐量调优就是减少垃圾收集器消耗的CPU周期数,从而将更多的CPU周期用于执行应用程序. CMS吞吐调优 CMS包 ...
- Java性能优化权威指南-读书笔记(三)-JVM性能调优-内存占用
新生代.老年代.永久代的概念不多说,这三个空间中任何一个不能满足内存分配请求时,就会发生垃圾收集. 新生代不满足内存分配请求时,发生Minor GC,老年代.永久代不满足内存分配请求时,发生Full ...
随机推荐
- 数据库之MySQL的基本使用
数据库简介 数据库 数据库就是一种特殊的文件,其中存储着需要的数据:关系型数据库核心元素: 数据行(记录) 数据列(字段) 数据表(数据行的集合) 数据库(数据表的集合) Ubuntu进入数据库: 1 ...
- Python笔记【5】_字符串&列表&元组&字典之间转换学习
#!/usr/bin/env/python #-*-coding:utf-8-*- #Author:LingChongShi #查看源码Ctrl+左键 #数据类型之间的转换 Str='www.baid ...
- 简单的 自动生成 二维码 PHP 方法
方法一:<style type="text/css">.eweima{ width:200px; height:200px; margin:auto;}</ ...
- leadcode的Hot100系列--617. 合并二叉树
合并,就是两个树的结构交集部分,数据相加,否则,取非空部分. 所以,这里相当于是对两棵树同时遍历: 如果两棵树节点都不为空,则数据相加, 否则,直接指针把不为空的节点复制过来. 注:这里没有申请内存, ...
- C语言学习书籍推荐《C陷阱与缺陷》下载
下载地址:点我 凯尼格 (作者), 高巍 (译者) <C和C++经典著作:C陷阱与缺陷>适合有一定经验的C程序员阅读学习,即便你是C编程高手,<C和C++经典著作:C陷阱与缺陷> ...
- ServiceFabric极简文档-3. 发布脚本
web: Trap { Write-Host $_.Exception.Message; Continue }; Connect-ServiceFabricCluster Remove-Service ...
- Jenkins Ci系列目录
Jenkins入门篇 1.Jenkins入门之界面概览 2.Jenkins入门之新建任务 3.Jenkins入门之导航操作 4.Jenkins入门之任务基本操作 5.Jenkins入门之执行Power ...
- [记录]inotifywait+rsync脚本和sersync2服务检测的脚本
1)inotifywait+rsync脚本: #!/bin/bash src=/data/ # 需要同步的源路径 des=data # 目标服务器上 rsync --daemon 发布的名称,rsyn ...
- BFM使用 - 获取平均脸模型的68个特征点坐标
使用版本:2009 数据说明网址:https://faces.dmi.unibas.ch/bfm/index.php?nav=1-1-0&id=details 数据下载网址:https://f ...
- [Linxu] Ubuntu下载mysql
//下载: sudo apt install mysql-server sudo apt install mysql-client sudo apt install libmysqlclient-de ...