2016-03-10 8 views
15

長年にわたって、+UseParallelOldGCを使用して適度なヒープサイズのJavaサービスを実行してきました。今度は、より大きなヒープとG1コレクタを使用して新しいサービスを展開し始めています。これはかなりうまくいく。Java G1:本番環境でのメモリリークの監視

+UseParallelOldGCを使用している私たちのサービスでは、収集後に古い世代のサイズを調べ、スレッシュホールドを警告してメモリリークを監視します。これはかなりうまく動作し、実際に2週間前にベーコンを保存しました。 getMax() と(利用可能な場合)"Old Gen"

  • で終わる名前を持つ

    • ManagementFactory.getMemoryPoolMXBeans()
    • MemoryPoolMXBean結果を検索するgetCollectionUsage().getUsed()の比較:

      具体的には、+UseParallelOldGCのために、我々は次のようにします

      残念ながら、G1にはもう012という概念がないようです。

      基本的には、最後に混在したコレクションの後にG1ヒープサイズを監視したいと思っています。

      たとえば、VMの外に、私は単に最後'(mixed)'がその'(young)'が続くと、最終的なヒープサイズが(例えば、'1540.0M' 'Heap: 3694.5M(9216.0M)->1540.0M(9216.0M)'

      いずれかがありましたものを見ていた見つかったawkスクリプトと幸せになりますJava VMの内部でこれを行う方法は?

  • +0

    これは同様の情報を提供する必要があります:http://stackoverflow.com/a/ 32509813/1362755 – the8472

    答えて

    2

    はい、JVMは、このような情報を取得するのに十分なツールを提供します。たとえば、あなたは、ガベージコレクションに関するすべての詳細を印刷し、このクラス(ただMemoryUtil.startGCMonitor()を呼び出す)のようなものを使用することができます

    public class MemoryUtil { 
    
        private static final Set<String> heapRegions; 
    
        static { 
         heapRegions = ManagementFactory.getMemoryPoolMXBeans().stream() 
           .filter(b -> b.getType() == MemoryType.HEAP) 
           .map(MemoryPoolMXBean::getName) 
           .collect(Collectors.toSet()); 
        } 
    
        private static NotificationListener gcHandler = (notification, handback) -> { 
         if (notification.getType().equals(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION)) { 
          GarbageCollectionNotificationInfo gcInfo = GarbageCollectionNotificationInfo.from((CompositeData) notification.getUserData()); 
          Map<String, MemoryUsage> memBefore = gcInfo.getGcInfo().getMemoryUsageBeforeGc(); 
          Map<String, MemoryUsage> memAfter = gcInfo.getGcInfo().getMemoryUsageAfterGc(); 
          StringBuilder sb = new StringBuilder(250); 
          sb.append("[").append(gcInfo.getGcAction()).append("/").append(gcInfo.getGcCause()) 
            .append("/").append(gcInfo.getGcName()).append("/("); 
          appendMemUsage(sb, memBefore); 
          sb.append(") -> ("); 
          appendMemUsage(sb, memAfter); 
          sb.append("), ").append(gcInfo.getGcInfo().getDuration()).append(" ms]"); 
          System.out.println(sb.toString()); 
         } 
        }; 
    
        public static void startGCMonitor() { 
         for(GarbageCollectorMXBean mBean: ManagementFactory.getGarbageCollectorMXBeans()) { 
          ((NotificationEmitter) mBean).addNotificationListener(gcHandler, null, null); 
         } 
        } 
    
        public static void stopGCMonitor() { 
         for(GarbageCollectorMXBean mBean: ManagementFactory.getGarbageCollectorMXBeans()) { 
          try { 
           ((NotificationEmitter) mBean).removeNotificationListener(gcHandler); 
          } catch(ListenerNotFoundException e) { 
           // Do nothing 
          } 
         } 
        } 
    
        private static void appendMemUsage(StringBuilder sb, Map<String, MemoryUsage> memUsage) { 
         memUsage.entrySet().forEach((entry) -> { 
          if (heapRegions.contains(entry.getKey())) { 
           sb.append(entry.getKey()).append(" used=").append(entry.getValue().getUsed() >> 10).append("K; "); 
          } 
         }); 
        } 
    } 
    

    をこのコードでは、gcInfo.getGcAction()はあなたに混合/主要なものからマイナーコレクションを分離するのに十分な情報を提供します。

    しかし、G1へのアプローチ(しきい値付き)を使用する際には重要な注意点があります。 G1の単一の混合コレクションは、通常、いくつかの古いgenリージョンにのみ影響します。GCのポーズを低く抑えるには、十分な量のメモリを解放するには十分なものが多く、あまり多くはありません。だから、G1の混合コレクションの後に、あなたのゴミがすべて消えてしまったと確信することはできません。結果として、メモリリークを検出するより洗練された戦略を見つける必要があります(コレクションの頻度に基づいて、複数のコレクションから統計を収集するなど)

    関連する問題