jmx的垃圾回收器次数揭秘

  

  对于jmx提供的垃圾回收器的次数,很多人的疑问点都是老年代的回收次数是否等于FGC的次数。下面我们就围绕这个问题来进行分析。

  jmx的提供以及用法

  api介绍

  public interface GarbageCollectorMXBean extends MemoryManagerMXBean {

  public long getCollectionCount();

  public long getCollectionTime();

  }

  jmx提供了gc次数和gc时间的接口。他们分别返回gc总次数以及gc总时间。

  for (GarbageCollectorMXBean garbageCollector : ManagementFactory.getGarbageCollectorMXBeans()) {

  //todo

  }

  使用方式也比较简单。

  认识垃圾回收器名称

  static GCMemoryManager* get_copy_memory_manager();//Copy

  static GCMemoryManager* get_parnew_memory_manager();//ParNew

  static GCMemoryManager* get_g1YoungGen_memory_manager();//G1 Young Generation

  static GCMemoryManager* get_psScavenge_memory_manager();//PS Scavenge

  static GCMemoryManager* get_psMarkSweep_memory_manager();//PS MarkSweep

  static GCMemoryManager* get_g1OldGen_memory_manager();//G1 Old Generation

  static GCMemoryManager* get_msc_memory_manager();//MarkSweepCompact

  static GCMemoryManager* get_cms_memory_manager();//ConcurrentMarkSweep

  以上就是列举jdk1.8中的垃圾回收器以及名字,前面4个是年轻代的。后面4个是老年代的。hotspot在1.8中还都是分代回收。所以jvm启动后会带有2个垃圾回收器。需要根据名字来获取对应的数据。

  查看数据来源

  以上的manager都是GCMemoryManager的子类。时间和次数都在父类的成员变量中,接下来的逻辑基本都是在父类中实现的。子类主要是提供名字的和算法种类。

  void MemoryService::gc_end(bool fullGC, bool recordPostGCUsage,

  bool recordAccumulatedGCTime,

  bool recordGCEndTime, bool countCollection,

  GCCause::Cause cause) {

  GCMemoryManager* mgr;

  if (fullGC) {

  mgr = (GCMemoryManager*) _major_gc_manager;

  } else {

  mgr = (GCMemoryManager*) _minor_gc_manager;

  }

  assert(mgr-is_gc_memory_manager(), Sanity check);

  // register the GC end statistics and memory usage

  mgr-gc_end(recordPostGCUsage, recordAccumulatedGCTime, recordGCEndTime,

  countCollection, cause);

  }

  这里有个判定,是fullgc的时候就会使用老年代垃圾回收器,次数和时间增加的逻辑就在 mgr-gc_end中。MemoryService::gc_end的调用也是很有意思的,写在了析构函数中。

  TraceMemoryManagerStats::~TraceMemoryManagerStats() {

  MemoryService::gc_end(_fullGC, _recordPostGCUsage, _recordAccumulatedGCTime,

  _recordGCEndTime, _countCollection, _cause);

  }

  现在问题就转变成什么时候生成TraceMemoryManagerStats的对象(对象销毁就会调用析构函数)。下面我们开始跟踪老年代的调用次数

  MarkSweepCompact

  void GenCollectedHeap::do_collection(bool full,

  bool clear_all_soft_refs,

  size_t size,

  bool is_tlab,

  int max_level) {

  ...

  TraceMemoryManagerStats tmms(_gens[i]-kind(),gc_cause());

  ...

  }

  msc就是老年代回收的时候,调用一次。是fullgc的次数。

  PS MarkSweep

  PS MarkSweep是垃圾回收器的名称,但是他有两种算法

  psMarkSweep

  单线程回收

  bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) {

  ...

  TraceMemoryManagerStats tms(true /* Full GC */,gc_cause);

  ...

  }

  psParallelCompact

  多线程回收

  bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) {

  ...

  TraceMemoryManagerStats tms(true /* Full GC */,gc_cause);

  ...

  }

  也在老年代垃圾回收器fullgc时进行增加次数

  cms

  TraceCMSMemoryManagerStats::TraceCMSMemoryManagerStats(CMSCollector::CollectorState phase, GCCause::Cause cause): TraceMemoryManagerStats() {

  switch (phase) {

  case CMSCollector::InitialMarking:

  initialize(true /* fullGC */ ,

  cause /* cause of the GC */,

  true /* recordGCBeginTime */,

  true /* recordPreGCUsage */,

  false /* recordPeakUsage */,

  false /* recordPostGCusage */,

  true /* recordAccumulatedGCTime */,

  false /* recordGCEndTime */,

  false /* countCollection */ );

  break;

  case CMSCollector::FinalMarking:

  initialize(true /* fullGC */ ,

  cause /* cause of the GC */,

  false /* recordGCBeginTime */,

  false /* recordPreGCUsage */,

  false /* recordPeakUsage */,

  false /* recordPostGCusage */,

  true /* recordAccumulatedGCTime */,

  false /* recordGCEndTime */,

  false /* countCollection */ );

  break;

  case CMSCollector::Sweeping:

  initialize(true /* fullGC */ ,

  cause /* cause of the GC */,

  false /* recordGCBeginTime */,

  false /* recordPreGCUsage */,

  true /* recordPeakUsage */,

  true /* recordPostGCusage */,

  false /* recordAccumulatedGCTime */,

  true /* recordGCEndTime */,

  true /* countCollection */ );

  break;

  default:

  ShouldNotReachHere();

  }

  }

  cms就比较奇特了,他的+1条件有3种,InitialMarking,FinalMarking,Sweeping。

  foreground

  void CMSCollector::collect_in_foreground(bool clear_all_soft_refs, GCCause::Cause cause) {

  checkpointRootsInitial(false);

  ...

  checkpointRootsFinal(false, clear_all_soft_refs,

  init_mark_was_synchronous);

  ···

  sweep(false);

  ···

  }

  在foreground模式下,3中情况都有调用,也是就说一次完整的foreground会造成垃圾器次数+3。不过这种情况触发条件还是比较苛刻的。

  background

  void CMSCollector::collect_in_background(bool clear_all_soft_refs, GCCause::Cause cause) {

  ...

  sweep(true);

  ...

  }

  background模式下只有一处调用。也就是说正常的cms回收,老年代垃圾回收器是+1的。

  G1

  bool G1CollectedHeap::do_collection(bool explicit_gc,

  bool clear_all_soft_refs,

  size_t word_size) {

  ...

  TraceMemoryManagerStats tms(true /* Full GC */,gc_cause);

  ...

  }

  G1的fullgc的时候老年代回收器会+1。这么没有mixed的事情,也就是说,只要参数设置合理,G1基本上是看不到老年代回收次数的。

  总结

  以上展示了各种老年代垃圾回收器jmx回收次数的采集。我们可以发现除了cms外,老年代垃圾回收的采集次数就是fullgc的次数。cms的老年代垃圾回收器的次数和jstat的fgc的值也是对不上的。需要根据gc日志来进行分析,不要单纯的看回收次数。


转载于:https://juejin.im/post/5bc06652f265da0ae74fa593

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值