JVM大小分配原理简介(易于新手理解)。
来源:互联网 发布:win 10服务器端口 编辑:程序博客网 时间:2024/06/14 06:14
JVM大小分配怎样才合理取决于某个具体应用的对象的存活模式。
这涉及到分代式GC的原理。最初为何要把GC堆划分为多个区域,以不同的频率来收集它们?本来就是为了让每次收集的效率都最大(在收集的区域里尽可能回收出可用空间)。如果一个应用里对象的存活模式满足弱分代假设,那么把新生对象放在同一个区域里,每次收集这个区域的效率都应该比较高(因为假设是新生对象活不了多久就死了)。
有人专门研究这个。可以用"java object demography"这组关键字来搜已有资料。
====================
举例:可能很多人都有一种印象,young gen应该比old gen小。笼统说确实如此,因为在最坏情况下young gen里可能所有对象都还活着,而如果它们全部都要晋升到old gen的话,那old gen里的剩余空间必须能容纳下这些对象才行,这就需要old gen比young gen大(否则young GC就无法进行,而必须做full GC才能应付了)。
实际上却不总是这样的。所谓“最坏情况”在很多系统里是永远不会出现的。调优就是要针对实际应用里对象的存活模式来破除这些“最坏情况”的假设带来的限制。
许多Web应用里对象会有这样的特征:
·(a) 有一部分对象几乎一直活着。这些可能是常用数据的cache之类的
·(b) 有一部分对象创建出来没多久之后就没用了。这些很可能会响应一个请求时创建出来的临时对象
·(c) 最后可能还有一些中间的对象,创建出来之后不会马上就死,但也不会一直活着。
如果是这样的模式,那young gen可以设置得非常大,大到每次young GC的时候里面的多数对象(b)最好已经死了。
想像一下,如果young gen太小,每次满了就触发一次young GC,那么young GC就会很频繁,或许很多临时对象(b)正好还在被是使用(还没死),这样的话young GC的收集效率就会比较低。要避免这样的情况,最好是就是把young gen设大一些。
那old gen怎么办?如果是上面说的情况,那old gen至少要足以装下所有长期存活的对象(a);同时也要留出一定的余地用来容纳young GC没能清理掉的临时对象。
这样,最后调整出来的结果很可能young GC反而比old gen大许多。这完全没问题。
只有(a)和(b)的话就完美了,现实中最头疼的就是针对(c)对象的调优。它们或许会经历多次young GC之后仍然存活,于是晋升到old gen;但晋升上去之后或许很快就又死掉了。
这种对象最好能不让晋升到old gen(可以让它们在survivor space里多来回倒腾几次再晋升,也就是想办法增加tenuring threshold;不过HotSpot VM里的GC不让外界对此多插手,想减小MaxTenuringThreshold很容易,想增加实际有效的tenuring threshold就没那么容易了)。但如果真的不让它们晋升,young GC的暂停时间就会增长(在survivor space里来回倒腾对象意味着要来回拷贝,这会花时间)。
所以有一种策略是尽量让这种对象的大部分在young GC中消耗掉(在保持young GC的暂停时间不超过某个预期值的前提下),而“漏”到old gen的那些让诸如CMS之类的并发GC来解决。
总之这里要做一定的tradeoff就是了。
=================
知道了原理之后在现实中要如何实践呢?
首先得了解硬性限制:某个服务器总共有多少内存,其中最多可以分配多少给某个应用程序;有没有一些服务对响应时间有严格要求,有的话限制是多少,之类的。
然后看看应用的特征是怎样的。可以借助一些工具来了解对象的存活情况,例如NetBeans的profiler就有这样的功能(老文档);许多其它主流Java profiler也有类似的功能。
这些工具的精度和性能开销各异,总之自己摸索下看看吧。
情况了解清楚了就可以开始迭代调整各种参数看实际运行的表现如何。迭代到满意为止。
要分析实际GC的运行状况,首要切入点就是分析GC日志。有很多工具能把HotSpot VM的GC日志可视化。我以前一直在用的是这个:GCHisto。
然后像Twitter做的这个工具也可以抽取一些GC的辅助统计信息:
这涉及到分代式GC的原理。最初为何要把GC堆划分为多个区域,以不同的频率来收集它们?本来就是为了让每次收集的效率都最大(在收集的区域里尽可能回收出可用空间)。如果一个应用里对象的存活模式满足弱分代假设,那么把新生对象放在同一个区域里,每次收集这个区域的效率都应该比较高(因为假设是新生对象活不了多久就死了)。
有人专门研究这个。可以用"java object demography"这组关键字来搜已有资料。
====================
举例:可能很多人都有一种印象,young gen应该比old gen小。笼统说确实如此,因为在最坏情况下young gen里可能所有对象都还活着,而如果它们全部都要晋升到old gen的话,那old gen里的剩余空间必须能容纳下这些对象才行,这就需要old gen比young gen大(否则young GC就无法进行,而必须做full GC才能应付了)。
实际上却不总是这样的。所谓“最坏情况”在很多系统里是永远不会出现的。调优就是要针对实际应用里对象的存活模式来破除这些“最坏情况”的假设带来的限制。
许多Web应用里对象会有这样的特征:
·(a) 有一部分对象几乎一直活着。这些可能是常用数据的cache之类的
·(b) 有一部分对象创建出来没多久之后就没用了。这些很可能会响应一个请求时创建出来的临时对象
·(c) 最后可能还有一些中间的对象,创建出来之后不会马上就死,但也不会一直活着。
如果是这样的模式,那young gen可以设置得非常大,大到每次young GC的时候里面的多数对象(b)最好已经死了。
想像一下,如果young gen太小,每次满了就触发一次young GC,那么young GC就会很频繁,或许很多临时对象(b)正好还在被是使用(还没死),这样的话young GC的收集效率就会比较低。要避免这样的情况,最好是就是把young gen设大一些。
那old gen怎么办?如果是上面说的情况,那old gen至少要足以装下所有长期存活的对象(a);同时也要留出一定的余地用来容纳young GC没能清理掉的临时对象。
这样,最后调整出来的结果很可能young GC反而比old gen大许多。这完全没问题。
只有(a)和(b)的话就完美了,现实中最头疼的就是针对(c)对象的调优。它们或许会经历多次young GC之后仍然存活,于是晋升到old gen;但晋升上去之后或许很快就又死掉了。
这种对象最好能不让晋升到old gen(可以让它们在survivor space里多来回倒腾几次再晋升,也就是想办法增加tenuring threshold;不过HotSpot VM里的GC不让外界对此多插手,想减小MaxTenuringThreshold很容易,想增加实际有效的tenuring threshold就没那么容易了)。但如果真的不让它们晋升,young GC的暂停时间就会增长(在survivor space里来回倒腾对象意味着要来回拷贝,这会花时间)。
所以有一种策略是尽量让这种对象的大部分在young GC中消耗掉(在保持young GC的暂停时间不超过某个预期值的前提下),而“漏”到old gen的那些让诸如CMS之类的并发GC来解决。
总之这里要做一定的tradeoff就是了。
=================
知道了原理之后在现实中要如何实践呢?
首先得了解硬性限制:某个服务器总共有多少内存,其中最多可以分配多少给某个应用程序;有没有一些服务对响应时间有严格要求,有的话限制是多少,之类的。
然后看看应用的特征是怎样的。可以借助一些工具来了解对象的存活情况,例如NetBeans的profiler就有这样的功能(老文档);许多其它主流Java profiler也有类似的功能。
这些工具的精度和性能开销各异,总之自己摸索下看看吧。
情况了解清楚了就可以开始迭代调整各种参数看实际运行的表现如何。迭代到满意为止。
要分析实际GC的运行状况,首要切入点就是分析GC日志。有很多工具能把HotSpot VM的GC日志可视化。我以前一直在用的是这个:GCHisto。
然后像Twitter做的这个工具也可以抽取一些GC的辅助统计信息:
阅读全文
0 0
- JVM大小分配原理简介(易于新手理解)。
- 网络地址转换NAT原理(易于理解)
- JVM的内存分配原理
- JVM原理简介
- 理解JVM运行原理
- 深入理解JVM原理
- JVM基础(一):内存空间分配及其回收原理
- JVM内存分配过程与原理解析(雷惊风)
- JVM基础(一):内存空间分配及其回收原理
- 深入理解JVM(一)-理解内存分配
- 【Java面试整理之JVM】深入理解JVM结构、类加载机制、垃圾回收GC原理、JVM内存分配策略、JVM内存泄露和溢出
- 模板测试(易于理解)
- java特点---系统易于表达、易于理解
- 理解内存分配原理分析
- JVM原理之内存分配参数
- Deep Learning-------流行网络框架DIY版本(易于理解)
- 寻找一种易于理解的一致性算法(扩展版)
- 寻找一种易于理解的一致性算法(扩展版)
- DedeCMS 5.7 ps2 前台同时搜索标题和简介内容
- python解决list unicode转中文显示
- Android-使用Android Studio实现第三方QQ登录
- 架构演进
- 高吞吐量的一个日志函数类_用于IOCP (Delphi)
- JVM大小分配原理简介(易于新手理解)。
- Xcode9学习笔记70
- 2-《解忧程序员》读后感
- 【01-Redis 介绍】
- 003 全概率公式与贝叶斯公式
- C++学习日记(1)
- [工作效率提升]焦虑性失眠的应对方法
- JavaCore-OOP-1-最最基础的商品管理
- Python对mysql的操作三