JVM Optimization
- 架构图
- 基本概念说明
- 堆(heap):数据存储,对象实例;空间往上增长,线程共享区;大小可通过-Xmx和-Xms配置
- 新生代(Young Generation):划分为Eden Space和两个Survivor(From Space 和To Space),new object首先存放在Eden区,Eden空间不足,进行GC,将存活的对象放到From Space;如果From Space已满,再进行GC,将存活的对象放到To Space;如果To Space已满,则再次GC,将存活的对象放入旧生代(Old Generation);可用-XX:survivorRatio控制Eden和Survivor的比例(默认值为8,即Eden占8/10, 另两个survivor各占1/10),或-Xmn配置新生代;-XX:NewSize和-XX:MaxNewSize分别代表新生代的初始值和最大值;
- 旧生代(Old Generation):存放新生代经过三次垃圾会后仍存活的对象,如果旧生代已满,进行FullGCC,如果FullGCC后仍然无法存储对象,则报OutOfMemoryError(原因:要么heap设置大小不够;要么应用创建太多对象,且由于被引用而长时间不能被回收);
- 持久代(Permanent Generation):存放类的元数据(方法、字段、类和包上描述数据,如注解Annotation,注释等,元数据可用于创建文档,跟踪代码中的依赖性如重构或重载,执行编译时检查,代码分析)、常量池、静态变量;如果出现OutOfMemoryError: PermGen space,原因有二:加载jar太多;或大量动态反射的类生成;可通过-XX:PermSize和-XX:MaxPermSize配置初始值和最大值;JDK1.8后将元数据移植到本地内存(好处:如多个项目的共享jar在本地内存只有一份),HotSopt VM为其分配或释放内存;可通过-XX:MetaspaceSize 和 -XX:MaxMetaspaceSize配置大小;
- JDK1.8后将元数据存放在Metaspace区域(本地内存,取代method area区域),常量池和静态变量仍在Heap的持久代中;
- 堆(heap):数据存储,对象实例;空间往上增长,线程共享区;大小可通过-Xmx和-Xms配置
- 栈(stack):程序执行,处理数据;空间动态增长(对象可垃圾回收),一个线程对应一个栈,每个方法对应一个frame,其中存储局部变量(局部变量区),方法返回值和程序运行产生的中间值(操作数栈)。基本类型长度固定(不会动态增长),需要空间较小,存放栈中;也存放对象引用;
Object ob =
new
Object()一个最基本的对象,占用空间:占的空间为:4byte(栈)+8byte(堆);如
Class A{
int
i;
boolean
b;
Object obj;
},其大小为:A(8byte)+int(4byte)+boolean(1byte)+引用(4byte)=17byte,但分配时为8的倍数,所以空间为24byte。
- PC Register:存储了下一条将要执行的指令;
- class load 机制
- 栈(stack):程序执行,处理数据;空间动态增长(对象可垃圾回收),一个线程对应一个栈,每个方法对应一个frame,其中存储局部变量(局部变量区),方法返回值和程序运行产生的中间值(操作数栈)。基本类型长度固定(不会动态增长),需要空间较小,存放栈中;也存放对象引用;
- Custom ClassLoader: 应用程序自定义的ClassLoader, 如Tomcat会根据J2EE规范自行实现ClassLoader加载过程中,会检查类是否已被加载(自下而上),只要某个ClassLoader已加载即可,否则会自上而下加载该类。
- Link:二进制字节码格式校验;静态变量默认值赋值;检验类、接口中属性和方法的存在,否则抛出NoSuchMethodError、NoSuchFieldError。
- Initialize: 静态初始化代码、构造器代码以及静态属性的初始化;new对象;反射调用类中的方法;子类调用了初始化;JVM启动过程中指定的初始化类。
- 清理Eden和Survior的GC叫Minor GC;清理old区域的叫Major GC;清理整个Heap的叫Full GC;
- 哪些对象可被回收:
- 引用计数算法:每创建一个对象,给其分配一个引用计数变量,并置值为1;当把该变量赋值给任何其它变量时,引用计数加1;当一个实例对象的引用生命周期结束或被修改时,该实例的引用计数减1;一个引用计数为零的对象将被垃圾回收,同时该对象引用其它对象的引用计数器减1。
- 缺点:无法检测出循环引用,如父对象有对子对象的引用,子对象也有对父对象的引用;
- 优点:执行效率高(可程序执行中交织进行)
- 可达分析算法:通过从对象GC ROOT的引用关系开始分析,逐层画出一个引用关系图节点图,最后剩余节点被认为没有引用到,可垃圾回收(还会进行两次标记,最后确定是否回收);GC ROOT对象包括:栈中引用对象;方法区中静态属性引用的对象;方法区中常量引用的对象;本地方法栈中JNI引用的对象;
- 引用分类:强引用(如Object obj = new object()),软引用,弱引用,虚引用,引用计数和可达分析算法都是基于强引用。
- 方法区中常量和类的回收:前者可通过可达性分析进行回收;后者需同时满足:该类所有实例是否都已回收?加载该类的ClassLoader是否已经回收?该类对应的java.lang.Class对象是否在别的地方有被引用(确定无反射访问)?
- 引用计数算法:每创建一个对象,给其分配一个引用计数变量,并置值为1;当把该变量赋值给任何其它变量时,引用计数加1;当一个实例对象的引用生命周期结束或被修改时,该实例的引用计数减1;一个引用计数为零的对象将被垃圾回收,同时该对象引用其它对象的引用计数器减1。
- 垃圾回收算法
- 标记-清除算法:使用从根集合(GC Roots)进行扫描,对存活的对象进行标记,完成标记后,再扫描整个空间,对没有标记的对象进行垃圾回收;该算法不需要移动对象,当存活对象较多时,该算法较为高效,但会产生内存碎片;
- 复制算法:为克服句柄开销和解决内存开销,将堆分为对象区和空闲区,当对象区已满,将对象区的存活对象复制到空闲区,这样将原来的对象区转变为空闲区,又可存放新的对象;
- 标记-整理算法:与标记-清除算法不同的是,在回收没有引用的对象后,将存活对象往左端空闲空间移动,同时更新对应指针;该算法成本较高,但解决了碎片问题;
- 分代收集算法(目前JVM常用算法):根据对象存活的生命周期,将对象划分为新生代(有大量对象回收)、老生代(较少对象回收)和永久代(不回收),不同代采用不同回收算法;
- 新生代分为eden+survior0+survior1(比例8:1:1),新生对象放在eden中,垃圾回收时(不一定eden满),将eden中存活的对象复制到survior0,然后清空eden,如果survior0满,则将eden和survior0中存活对象复制到survior1,然后清空eden和survior0,再交换survior1和survior0(此时survior0为空),保持survior1为空,再循环以上过程;如果survior1不能存放eden和survior0中存活对象时,将存活对象复制到老年代;如果老年代也满,即触发Major GC(Full GC),新生代和老年代都进行垃圾回收(新生代叫Minor GC,频率较高)。
- 老年代存放生命周期较长的对象(在新生代经过多次垃圾回收仍然存活的对象),内存空间大概是新生代2倍或以上。
- 持久代存放静态文件,如java类,垃圾回收对该区没有多大影响;如果应用动态生成有大量类或调用累,需要将该区设置一个较大空间。
- 垃圾收集器
- 串行收集器(Serial Collector,复制算法):新生代单线程收集器(标记和清除都是单线程),是client模式默认的GC,简单高效,也可通过-XX:+UseSerialGC强制指定别的GC方式;
- 串行老年代收集器(Serial Old Collector,清除-标记算法):老年代单线程收集器;
- 并行新生代收集器(ParNew Collector,停止-复制算法):新生代并行收集器,在多核CPU环境下,比串行收集器效率更高;
- Parallel Scavenge收集器(停止-复制算法):并行收集器,高效利用CPU以获得高吞吐量(用户线程时间/(用户线程时间+GC线程时间)),server模式默认采用的GC方式;可用-XX:+UseParallelGC和-XX:ParallelGCThreads指定GC方式和GC线程数;
- Parallel Old Scavenge收集器(停止-复制算法):老年代并行收集器(吞吐量优先);
- CMS收集器(Concurrent Mark Sweep,标记清理算法):高并发,低停顿(GC回收时暂停应用),响应快,尤适合多CPU。
- Scanvenge GC和Full GC
- 当Eden申请新生成对象空间失败时会出发Scanvenge GC;
- 4种情况触发Full GC:年老带已满(Tenured);持久代已写满(Perm);System.gc()被显示调用;上一次GC后Heap各域分配策略动态变化;
- 执行引擎(Execution Engine):字节码由一个个指令单元组成,每个指令有一个字节的操作码和操作数组成,执行引擎逐一读取这些指令;但字节码语言是人类可以理解的语言,需要再将bytecode转化成JVM machine能执行的语言;
- 解释器(Interpreter):逐一读取、解释、执行字节码指令;可迅速解释一条指令,但执行指令较慢;
- JIT (Just-In-Time) compiler:作为补偿Interpreter的一种手段,首先运行Interpreter, 然后在合适的时机,将所有的bytecode转化为native code直接执行,而且native code保存在缓存中,所以执行效率很高。
- HotSpot采用编译器和解释器混合使用,HotSpot会将一些频繁调用的方法和代码(也叫热点代码Hot Spot Code)在运行时编译成native code;HotSpot内置两个编译器:client compiler(C1)和server compiler(C2), 程序采用哪个取决于JVM的运行模式设置;
- 为了平衡启动响应速度和运行效率,HotSpot会采取逐层编译机制(Tiered compilation),JDK1.7的server complier默认开启该机制:
JVM垃圾回收过程:垃圾回收的频率和时间是检验程序运行好坏的标准(因为回收时要停顿应用);
第0层:程序解释执行,解释器不开启性能监控,可触发第一层编译。
第1层:也称为C1编译(更好的编译速度),将字节码编译为本地代码,进行简单、可靠的优化。
第2层:也称为C2编译(更好的编译质量),也是将字节码编译为本地代码,但会启用一些编译耗时较长的优化,甚至会根据性能监控信息进行一些不可靠的激进优化。
- 补充说明1:基本类型byte,boolean(1 byte),short,char(2 bytes),int,float(4 bytes),long,double(8 bytes);
JVM Optimization的更多相关文章
- Q&A to prepare interview of HSBC
1.How do you keep updating lastest IT knowledge? 1).keep an eye on current project technology evetho ...
- Tomcat APR & Linux Optimization
一.简介 APR(Apache portable Run-time libraries)模式:简单理解,就是从操作系统级别解决异步IO问题,大幅度的提高服务器的处理和响应性能, 也是Tomcat运行高 ...
- 关于JVM的类型和模式
原文出处: 摆渡者 引言 曾几何时,我也敲打过无数次这样的命令: 然而之前的我都只关心过版本号,也就是第一行的内容.今天,我们就来看看第3行输出的内容:JVM的类型和工作模式. 其实说Server和C ...
- Java Performance Optimization Tools and Techniques for Turbocharged Apps--reference
Java Performance Optimization by: Pierre-Hugues Charbonneau reference:http://refcardz.dzone.com/refc ...
- java源码剖析: 对象内存布局、JVM锁以及优化
一.目录 1.启蒙知识预热:CAS原理+JVM对象头内存存储结构 2.JVM中锁优化:锁粗化.锁消除.偏向锁.轻量级锁.自旋锁. 3.总结:偏向锁.轻量级锁,重量级锁的优缺点. 二.启蒙知识预热 开启 ...
- java jvm和android DVM区别
本文转自:http://blog.csdn.net/yujun411522/article/details/45932247 1.Android dvm的进程和Linux的进程, 应用程序的进 ...
- jvm.option是什么,它是如何加载的
jvm.option是一些程序里边的java的配置参数的一个集合,不同的应用都会定义自己的jvm.options用来控制一些jvm的参数 以下,以elasticsearch为例,来说明它是如何加载的 ...
- JVM致命错误日志(hs_err_pid.log)分析
当jvm出现致命错误时,会生成一个错误文件 hs_err_pid<pid>.log,其中包括了导致jvm crash的重要信息,可以通过分析该文件定位到导致crash的根源,从而改善以保证 ...
- New JVM Option Enables Generation of Mixed-Mode Flame Graphs
转自 https://www.infoq.com/news/2015/08/JVM-Option-mixed-mode-profiles Java has added a new launch opt ...
随机推荐
- android layout文件优化
性能优化1--UI优化 1.使用系统为我们提供了几个抽象的标签①include:重用include中layout属性指定一个外部布局文件,通过该方式则不需要把这个布局文件在该代码中重复的写一遍了. 若 ...
- Flask最强攻略 - 跟DragonFire学Flask - 第十五篇 Flask-Script
其实本章就是为下一章做的铺垫啦,但是也要认真学习哦 Flask-Script 从字面意思上来看就是 Flask 的脚本 是的,熟悉Django的同学是否还记得Django的启动命令呢? python ...
- c#查找窗口的两种办法
原文最早发表于百度空间2009-06-17 1.process.MainWindowTitle(这个只能获取一部分窗口)2.EnumWindows(用windows API)
- Idea 全局替换指定字符
最近使用idea开发,刚接触不久,然后碰到需要全局替换的时候,懵逼了.之前使用eclipse 直接Ctrl+F 就可以操作了. 现在使用idea 摁Ctrl+F竟然只能搜,不能替换....尴尬的一匹. ...
- Guitar Pro里的编谱方式怎么用?
今天来教大家如何使用Guitar Pro中的编谱方式来让我们的乐谱更加美观整齐耐看,我们一起get起来吧! 相信我们每一个人在使用Guitar Pro进行编曲创作时,都会碰到这种情况,在乐谱上,会看到 ...
- Java 基础 - 集合
Set 集合 Set 集合通常不能记住元素的添加顺序.Set 集合不允许包含相同的元素. HashSet 是 Set 接口的实现类,按照 Hash 算法存储集合中的元素.HashSet 不是同步的,如 ...
- WordPress上传到互联网搭建
1.建站流程: 1.购买域名 2.购买空间 3.解析绑定 4.上传安装 2.购买域名 域名的购买可以到相关域名出售的服务商那儿买,如阿里云,主机庙.这里就不做详细解释了 3.购买空间 域名的购买可以到 ...
- [python]windows截图
Windows截图 截图:截取屏幕任意大小图片 下载pip install Pillow from PIL import ImageGrab # x1:开始截图的x坐标 # x2:开始截图的y坐标; ...
- 开机自动启动WEB服务,共享目录。
最近工作中,需要共享一个目录,每次重启总要手动执行一下 nohup python -m SimpleHTTPServer 8000这个命令,想着实现让它开机自动启动,就一劳永逸了. 手动步骤如下: ...
- guxh的python笔记四:迭代
1,可迭代对象iterable,迭代器iterator,生成器generator 可迭代对象iterable: 实现__iter__方法的类.__iter__方法返回iterator或者generat ...