最近开始优化页游服务端的性能,一些心得总结一下。如今的服务器硬件愈来愈好,几十G内存,十几个CPU。当硬件不是瓶颈的时候,若是让程序发挥最大效用就成了咱们须要考虑的问题。就游戏服务器来讲,得知足几个要求,高负载,低延时。特别是在开服当天,大量用户会涌进来,可能给服务器形成压力。使用Java做为服务器语言,除了程序自己的性能外,JVM的配置也直接影响到系统性能。java
参数调优算法
入门级别的配置通常是:java -server -Xmx5000m Xms5000m
服务器端的jvm运行程序记得都最好加上 -server 不少默认参数都会根据这个运行模式来优化。这里设置了最大内存和最小内存,通常都是配置成相同的,能够减小内存申请和伸缩带来的性能损耗服务器
加入垃圾回收算法的配置:java -server -Xmx5000m -Xms5000m -XX:+UseConcMarkSweepGC -XX:+UseParNewGC
关于垃圾回收的具体算法介绍我这里就不详细描述了,咱们都有一个常识,就是尽可能减小JVM的full gc的次数和时间,由于full gc 会致使整个系统的暂停(stop the world).为此,咱们为老年代选择了UseConcMarkSweepGC 选择了并发gc算法,也为新生代选择了多线程的并行gc算法UseParNewGC。多线程
设置新生代的内存大小 java -server -Xmx5000m -Xms5000m -Xmn800m -XX:+UseConcMarkSweepGC -XX:+UseParNewGC
Xmn是新生代的内存大小,包括(eden+ 2 survivor space)。这个参数设置直接影响系统的响应速度。在java程序中new一个对象,首先是放在eden区域,eden满了后,触发gc,存活下来的对象被拷贝到survivor区。通过若干次yong gc后,若是依然存活下来,就会进入老年代。新生代设置大了,会致使一次yong gc的时间消耗大,设置小了,又会很快满了,致使yong gc的频率太高。新生代不宜设置过大,由于新生代大了,老年代的内存就小了,老年代内存小,会致使full gc发生的频率变大。Xmn也没有一个确切的算法,根据你自身的业务系统决定的。我在设置的游戏服务器的时候,通常采用模拟大量并发用户的行为,调整Xmn的大小,同时监控gc的时间和频率,选择一个合适的大小。下面我会提到怎么用工具来监控gc。架构
设置一些额外的高级参数 java -server -Xmx5000m -Xms5000m -Xmn800m -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+UseCMSCompactAtFullCollection -XX:CMSInitiatingOccupancyFraction=70
使用CMS进行老年代gc,会容易致使一些内存碎片,致使内存利用率下降,为此,加入 UseCMSCompactAtFullCollection 能够保证在full gc时进行内存压缩,减小内存碎片,系统默认为开启true。CMSInitiatingOccupancyFraction=70 表示老年代内存达到70%时触发。这个参数要特别当心,默认为68%,设置得太小会致使full gc没有完成,yong gc的对象迁移过来,致使整个老年代内存都满了并发
5.-XX:+UseCompressedOops JVM优化之压缩普通对象指针(CompressedOops),一般64位JVM消耗的内存会比32位的大1.5倍,这是由于对象指针在64位架构下,长度会翻倍(更宽的寻址)。对于那些将要从32位平台移植到64位的应用来讲,平白无辜多了1/2的内存占用,这是开发者不肯意看到的。系统默认为开启true。jvm
6.-XX:+PrintCommandLineFlags 。这个参数的做用是显示出VM初始化完毕后全部跟最初的默认值不一样的参数及它们的值。工具
8.-XX:+PrintFlagsInitial 。这个参数显示在处理参数以前全部可设置的参数及它们的值性能
查看默认值的方式统一为
java -server -Xmx1024m -Xms1024m -XX:+UseConcMarkSweepGC -XX:+PrintFlagsFinal -version| grep ParallelGCThreads
JVM默认垃圾回收策略,
针对年轻代:
UseParallelGC true(默认)
UseParNewGC false
UseSerialGC false
-XX:+UseParallelGC:选择垃圾收集器为并行收集器。此配置仅对年轻代有效。能够同时并行多个垃圾收集线程,但此时用户线程必须中止。
-XX:+UseParNewGC:设置年轻代为多线程收集。可与CMS收集同时使用。在serial基础上实现的多线程收集器。
针对年老代:
UseParallelOldGC true(默认)
UseConcMarkSweepGC false
-XX:-UseConcMarkSweepGC 对老生代采用并发标记交换算法进行GC
-XX:+UseParallelOldGC:配置年老代垃圾收集方式为并行收集。当-XX:-UseParallelGC启用时该项自动启用
工具测试
jstat 用来实时查看gc的状态,
用法:jstat -gcutil 进程号 时间(毫秒)。结果以下:
里面列出每一个区间的内存大小,新生代gc的次数和时间,老年代gc的次数和时间。这里都能反映出你的JVM的运行情况
jmap 用于查看java进程的对象情况
用法:jmap -histo:live 进程id 。能够打印每一个类的实例数量,内存大小
用法:jmap -dump:format=b,file=log.bin 进程id 这个命令特别有用,能够将jvm的整个内存镜像拷贝下来,用于分析每一个对象占用的内存情况。当你的java进程崩溃了,用这个方法,能够分析出哪些对象是罪魁祸首
jstack 用于查看java进程id的堆栈信息
用法:jstack 进程id 这个工具对于查看死循环的线程颇有效,能够直接找出是哪一个线程在哪一个方法内死循环了
总结
JVM的参数有不少,大部分咱们都不须要去设置和优化。若是你的程序没有问题,就不要去折腾。若是你要优化,必定要有相应的测试流程来支撑。