jvm 说明
jvm既 Java Virtual Machine,既然是虚拟机,其必有存储空间,且不同的存储空间,存储特定的数据,如图所示:
- 虚拟机栈:存储基本数据类型、引用对象的变量、局部变量表等,这是线程私有的,每个线上线程的大小默认为1Mb。
- 程序计数器:存储字节指令的地地址,如果是本地方法栈,则存储undefined。
- 本地方法栈:由于java时表层语言,无法直接访问硬件,需要调用第三方语言,比如C、C++来操作硬件,比如创建内核线程,操作文件等。
- 方法区:存储jvm编译后地字节码文件,静态变量,常量,类信息等。
- 堆:
- 这是一块很重要的存储区域,也是我们性能调优重要依据,其用来存储java对象,gc回收地也是这一块数据。其分为老年代和新生代,默认数据大小为2 :1。
- 新生代又分为Eden区,s0区,s1区,默认数据大小为8 : 1 : 1。
- 新创建一个对象,首先判断能否放到Eden区,如果Eden区满了,会触发mirrorGc「所有的 Minor GC 都会触发“全世界的暂停(stop-the-world)”,停止应用程序的线程,但这段时间可以忽略不计」。此时Eden区和s0区中存活的对象移至s1区,并标志对象的分代年龄,eden区和s0区清空,如果此时对象还无法放置eden区,则直接放置老年代。反之亦然。
- 分代年龄存储到java对象头中。如果old区满了,会触发fullGc,我们尽量避免fullGc「fullGc暂停所有正在执行的线程(Stop The World),来回收内存空间,这个时间需要考虑地」。
因而,我们所说的性能调优,那么就是堆中的性能调优。
性能调优案例
假设,现在有亿级流量电商的抢购活动,活跃用户为500万,付费转化率未10%。活跃时间在抢购的前几分钟,假设每秒产生1000单,而每台Tomcat的最高并发支持数为500,现有三台服务器,均为4核8g,每台服务器均部署Tomcat,使用nginx做负载均衡,有300单落在服务器1上,每单所在堆空间大小为1Kb,每秒大约产生300Kb的堆对象。可以使用lucene来动态计算javabean所在堆空间的大小。下单还会产生其他对象,比如优惠券、库存、积分等,此时放大20倍,也就是每秒产生6000Kb的对象。假设还会有订单查询的操作,此时再放大10倍,也就是每秒产生约58MB的对象。如图所示:
此时,堆初始值大小和最大值大小均为3072MB,老年代大小为2048MB,新生代大小为1024MB,Eden区大小为819MB,s0和s1区大小均为102MB。819Mb / 58Mb = 14秒,大约14秒Eden区爆满,触发mirrorGc,此时停止应用程序的线程。因而,此时需要调整JVM的配置参数,老年代大小为1024MB,新生代大小为2048MB,Eden区大小为1638MB,s0和s1区大小均为204MB。1638Mb/ 58Mb = 28秒,这样会减少mirrorGc,从而达到优化的效果。但更多的优化可根据实际线上jvm运行情况来看。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/99085.html