zoukankan      html  css  js  c++  java
  • 游戏服务器如何防止OOM异常

    OOM异常是java.lang.OutOfMemoryError:Java heap space的简称,即堆内存溢出。在启动游戏服务的时候,一般会指定JVM的内存大小上限,比如:java -Xms512m -Xmx512m -Xmn256m xxx.jar :

    • -Xmx512m:设置JVM最大可用内存为512M.
    • -Xms512m:设置JVM促使内存为512M.此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存.
    • -Xmn256:设置年轻代大小为256,.整个堆大小=年轻代大小 + 年老代大小 + 持久代大小.持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小.此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8
      如果服务器在运行过程中,内存的使用量超过上面配置的JVM最大可用内存,就会出现OOM的异常。那么如果防止这种异常出现呢。
      首先,我们先明确一下引起这种异常的条件:
    1. 业务量过多,导致内存中数据太多,配置的JVM堆内存太小
    2. 就是传说中的内存泄漏,比如服务器中有些缓存只增不减,一直到内存不足。
    3. 某个资源被无限使用,比如线程被无限创建。

    所以为了防止游戏服务器上线之后,由于用户数量越来越多,操作越来越频繁产生OOM异常,在游戏服务器上线之前一定要做充足的压力测试。在压力测试的时候,可以通过观察内存对象数量的变化,查看是否有内存泄漏。如果没有内存泄漏,就要计算一下配置的JVM堆适应的用户上限,这样服务器上线之后,可以预估同时在线人数,配置相应的JVM堆大小。

    根据内存使用情况查看

    • 查看JVM配置与使用情况

    如果Java环境是JDK8或以下版本,使用命令:jmap -heap pid,pid表示要查看的进程号,例如:jmap -heap 2334
    如果Java环境是JDK8以上版本,使用命令:jhsdb jmap --heap --pid yourPId,例如:jhsdb jmap --heap --pid 2343
    这两个命令会打印当前进程的内存配置与使用详情,如下面所示:(我的环境是jdk10)

    Attaching to process ID 17674, please wait...
    Debugger attached successfully.
    Server compiler detected.
    JVM version is 10.0.1+10
    
    using thread-local object allocation.
    Garbage-First (G1) GC with 4 thread(s)
    
    Heap Configuration:
       MinHeapFreeRatio         = 40
       MaxHeapFreeRatio         = 70
       MaxHeapSize              = 1073741824 (1024.0MB)
       NewSize                  = 1363144 (1.2999954223632812MB)
       MaxNewSize               = 643825664 (614.0MB)
       OldSize                  = 5452592 (5.1999969482421875MB)
       NewRatio                 = 2
       SurvivorRatio            = 8
       MetaspaceSize            = 21807104 (20.796875MB)
       CompressedClassSpaceSize = 1073741824 (1024.0MB)
       MaxMetaspaceSize         = 17592186044415 MB
       G1HeapRegionSize         = 1048576 (1.0MB)
    
    Heap Usage:
    G1 Heap:
       regions  = 1024
       capacity = 1073741824 (1024.0MB)
       used     = 295734056 (282.03397369384766MB)
       free     = 778007768 (741.9660263061523MB)
       27.54238024353981% used
    G1 Young Generation:
    Eden Space:
       regions  = 33
       capacity = 253755392 (242.0MB)
       used     = 34603008 (33.0MB)
       free     = 219152384 (209.0MB)
       13.636363636363637% used
    Survivor Space:
       regions  = 1
       capacity = 1048576 (1.0MB)
       used     = 1048576 (1.0MB)
       free     = 0 (0.0MB)
       100.0% used
    G1 Old Generation:
       regions  = 249
       capacity = 284164096 (271.0MB)
       used     = 259033896 (247.03397369384766MB)
       free     = 25130200 (23.966026306152344MB)
       91.15644785750835% used
    
    37933 interned Strings occupying 2777136 bytes.
    

    由此可以判断JVM内存是否配置过小,或内存分配不良

    • 查看是否有内存泄漏

    查看是否有内存泄漏,就是要找到哪个对象在内存中最大或数量最多,找到这个对象之后,就需要在代码中查看都对这个对象做了哪些操作,是否是只有增加没有减少。
    可以使用命令:jmap -histo:live pid | more,其中,pid是要查看的进程id,它输出如下所示:

    num     #instances         #bytes  class name (module)
    -------------------------------------------------------
       1:       1326424       57739472  [B (java.base@10.0.1)
       2:       1321229       31709496  java.lang.String (java.base@10.0.1)
       3:        305884       24788952  [Ljava.util.HashMap$Node; (java.base@10.0.1)
       4:        346683       16640784  java.util.HashMap (java.base@10.0.1)
       5:        510859       16347488  java.util.HashMap$Node (java.base@10.0.1)
       6:        186800       12360448  [Ljava.lang.Object; (java.base@10.0.1)
       7:        262046        6289104  com.xinyue.util.BadWordsFilter$Node
       8:        172722        4145328  java.util.ArrayList (java.base@10.0.1)
       9:         86594        3463760  com.xinyue.common.dataconfig.OldPlayer
      10:        139967        3359208  com.google.common.collect.ImmutableMapEntry
      11:          4799        2346088  [I (java.base@10.0.1)
      12:           414        1855664  [Lcom.google.common.collect.ImmutableMapEntry;
      13:          4730        1730512  [C (java.base@10.0.1)
      14:         11874        1444664  java.lang.Class (java.base@10.0.1)
      15:         56537        1356888  com.google.common.collect.ImmutableMapEntry$NonTerminalImmutableMapEntry
      16:         81115        1297840  com.alibaba.fastjson.JSONObject
      17:          8951        1288944  com.xinyue.common.dataconfig.EnemyInfo
      18:         51979        1247496  com.xinyue.common.dataconfig.ForbiddenName
      19:         51103        1226472  com.alibaba.fastjson.JSONArray
      20:         34108        1091456  java.util.concurrent.ConcurrentHashMap$Node (java.base@10.0.1)
    --More--
    

    从这里可以看到每个对象的实例数量,占用内存大小。上面的例子中,属于业务代码占用内存最大的数是:com.xinyue.util.BadWordsFilter$Node,只要查看一下自己的代码,看看这里发生了什么操作,就可以知道是否会产生内存泄漏了。

    使用监控工具

    另外在测试环境下,可以使用监控工具,时时查看JVM使用情况,比较有名的一个是JProfiler,JProfiler是由ej-technologies GmbH公司开发的一款性能瓶颈分析工具(该公司还开发部署工具)。
    其特点:

    • 使用方便
    • 界面操作友好
    • 对被分析的应用影响小
    • CPU,Thread,Memory分析功能尤其强大
    • 支持对jdbc,noSql, jsp, servlet, socket等进行分析
    • 支持多种模式(离线,在线)的分析
    • 跨平台,支持 Windows MacOS,Linux,FreeBSD等。

    这个工具的详细用法由于篇幅所限,以后再说,有兴趣的朋友可以先研究一下。

  • 相关阅读:
    启动 YARN 并运行 MapReduce 程序(伪分布式模式)
    启动 HDFS 并运行 MapReduce 程序(伪分布式模式)
    简单计算器(stack)
    Linux定时发邮件脚本
    HttpClient接口调用-客户端
    获取时间字符串
    Visual Assist代码高亮突然失效
    批量快速生成员工文件夹工具
    日语学习笔记整理(汉译日)
    有关使用PLSQL Developer时出现报错ora-12514解决的方法
  • 原文地址:https://www.cnblogs.com/wgslucky/p/11764100.html
Copyright © 2011-2022 走看看