一、问题:如何在高性能服务器上进行JVM调优?

          方案一:采用64位操作系统,并为JVM分配大内存;

          方案二:选择使用32位JDK集群来充分利用高性能机器的硬件资源。(可以是docker或者其他)

         视频讲解:https://www.bilibili.com/video/av44880257/?p=17

二、方案一>>64位jvm+大内存

       我们知道,如果JVM中堆内存太小,那么就会频繁地发生垃圾回收,而垃圾回收都会伴随不同程度的程序停顿,因此,如果扩大堆内存的话可以减少垃圾回收的频率,从而避免程序的停顿。因此,人们自然而然想到扩大内存容量。而32位操作系统理论上最大只支持4G内存,64位操作系统最大能支持128G内存,因此我们可以使用64位操作系统,并使用64位JVM,并为JVM分配更大的堆内存。但问题也随之而来。堆内存变大后,虽然垃圾收集的频率减少了,但每次垃圾回收的时间变长。如果对内存为14G,那么每次Full GC将长达数十秒。如果Full GC频繁发生,那么对于一个网站来说是无法忍受的。因此,对于使用大内存的程序来说,一定要减少Full GC的频率,如果每天只有一两次Full GC,而且发生在半夜, 那完全可以接受。要减少Full GC的频率,就要尽量避免太多对象进入老年代,可以有以下做法:

    1、确保对象都是“朝生夕死”的 
          一个对象使用完后应尽快让他失效,然后尽快在新生代中被Minor GC回收掉,尽量避免对象在新生代中停留太长时间。
   2、提高大对象直接进入老年代的门槛 
         通过设置参数-XX:PretrnureSizeThreshold来提高大对象的门槛,尽量让对象都先进入新生代,然后尽快被Minor GC回收掉,而不要直接进入老年代。 

   注意:使用64位JDK的注意点
    1)64位JDK支持更大的堆内存,但更大的堆内存会导致一次垃圾回收时间过长。
    2)现阶段,64位JDK的性能普遍比32位JDK低。
    3)堆内存过大无法在发生内存溢出时生成内存快照 
    4)若将堆内存设为10G,那么当堆内存溢出时就要生成10G的大文件,这基本上是不可能的。
    5)相同程序,64位JDK要比32位JDK消耗更大的内存 

三、方案二>>使用32位JVM集群

      针对于64位JDK种种弊端,我们更多选择使用32位JDK集群来充分利用高性能机器的硬件资源。(注:只有一台服务器,集群是基于这台服务器的硬件资源虚拟出来的,docker或者esxi)在一台服务器上运行多个服务器程序,这些程序都运行在32位的JDK上。然后再运行个服务器作为反向代理服务器,由它来实现负载均衡。 由于32位JDK最多支持2G内存,因此每个虚拟结点的堆内存可以分配1.6G,一共运行10个虚拟结点的话,这台物理服务器可以拥有16G的堆内存。 缺点如下:
      1)多个虚拟节点竞争共享资源时容易出现问题 ,如多个虚拟节点共同竞争IO操作,很可能会引起IO异常。
      2)很难高效地使用资源池 ,如果每个虚拟节点使用各自的资源池,那么无法实现各个资源池的负载均衡。如果使用集中式资源池,那么又存在竞争的问题。

四、补充知识

        知识点:32位操作系统和64位操作系统的区别     

   1、32位系统CPU一次可处理32位数据,即一次处理4个字节。

         64位系统CPU一次可处理64位数据,即一次处理8个字节。

         通俗一点说: 32位,就相当于你拥有32个工人,每次能完成32个工人的工作量

                               64位,就相当于你拥有64个工人,每次能完成64个工人的工作量

         总结: 由32位系统过渡到64位系统,CPU处理数据能力提升了一倍。

    2、来说说寻址能力

     内存中一个地址占用8bit,即一个字节,32位cpu含有32根地址线,寻址能力为2的32次方个字节,相当于4G内存(所以,如果我们装32位系统,安装8G内存实际上是没有用的)。而64位cpu理论上寻址能力为2的64次方个字节,但目前硬件还达不到这个水准,当然我们用不了这么大的内存。

      64位系统下运行64位软件比32位系统运行32位软件要快,
      但是,64位系统运行32位软件跟32位系统运行32位软件速度应该是一样的 。

      总结: 64位CPU有更大的寻址能力。