2016-03-10 23 views
15

Yıllar boyunca, +UseParallelOldGC'u kullanarak mütevazı yığın boyutlarıyla Java hizmetleri çalıştırıyoruz. Şimdi, daha büyük bir yığın ve G1 toplayıcı kullanarak yeni bir hizmet sunmaya başlıyoruz. Bu oldukça iyi gidiyor.Java G1: Üretimde bellek sızıntılarının izlenmesi

+UseParallelOldGC kullanan hizmetlerimiz için, bir eşik üzerinde toplama ve uyarı yapıldıktan sonra eski nesil boyutuna bakarak bellek sızıntılarını izleriz. Bu oldukça iyi çalışıyor ve aslında iki hafta önce pastırmamızı kurtardı.

  • ManagementFactory.getMemoryPoolMXBeans()
  • adı
  • "Old Gen" biten ile MemoryPoolMXBean sonucu ara getMax()
ile (varsa) getCollectionUsage().getUsed() karşılaştırın:

Özellikle, +UseParallelOldGC için, biz aşağıdakileri yapın

Maalesef G1'in artık 012 konseptine sahip olmadığı anlaşılıyor.. Bununla birlikte, temel olarak, karışık bir döngüde ya da benzer bir şekilde yapmayı seçtiği son karma koleksiyonu takiben G1 yığın boyutunu izlemek isteriz.

Örneğin, VM dışında Ben sadece son '(mixed)' bir '(young)' izledi ve son yığın boyutu ne görünecek edildi bulunan bir awk komut dosyası ile mutlu olurdu (örneğin '1540.0M' 'Heap: 3694.5M(9216.0M)->1540.0M(9216.0M)')

var mı uygulanıyor Java VM içinde bunu yapmanın yolu nedir?

+0

bu, benzer bilgiler sağlamalıdır: http://stackoverflow.com/a/ 32509813/1362755 – the8472

cevap

2

Evet, JVM size G1 için bu bilgileri almak için yeterli araç sunar. Örneğin, çöp koleksiyonları hakkında tüm ayrıntıları yazdırır Bu sınıfta (sadece MemoryUtil.startGCMonitor() call) gibi bir şey kullanabilirsiniz:

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; "); 
      } 
     }); 
    } 
} 

Bu kodda, gcInfo.getGcAction() size karışık/majör olanlardan minör koleksiyonlarını ayırmak için yeterli bilgi verir.

Ancak, yaklaşımınızı (eşik ile) G1'e kullanmanın önemli bir uyarısı var. G1'deki tek bir karma koleksiyon genellikle sadece birkaç eski gen bölgesini etkiler - çok az miktarda bellek serbest bırakmaya yetecek kadar, ancak GC'nin düşük tutulması için çok fazla değil. Yani, G1'deki karışık bir koleksiyondan sonra tüm çöplerin gittiğinden emin olamazsınız. Sonuç olarak, bellek sızıntılarını saptamak için daha karmaşık bir strateji bulmanız gerekebilir (belki koleksiyonların sıklığına, farklı koleksiyonlardan istatistik toplamaya, vb.).