Skip to content

jcmd jstat gc

ceragon edited this page Jun 29, 2022 · 5 revisions

jstat gc

gc 统计变量

perf 映射表

name perf key jvm var
S0C sun.gc.generation.0.space.1.capacity no used
S1C sun.gc.generation.0.space.2.capacity to_counters
S0U sun.gc.generation.0.space.1.used no used
S1U sun.gc.generation.0.space.2.used to_counters
EC sun.gc.generation.0.space.0.capacity eden_counters
EU sun.gc.generation.0.space.0.used eden_counters
OC sun.gc.generation.1.space.0.capacity old_space_counters
OU sun.gc.generation.1.space.0.used old_space_counters
MC sun.gc.metaspace.capacity
MU sun.gc.metaspace.used
CCSC sun.gc.compressedclassspace.capacity
CCSU sun.gc.compressedclassspace.used
YGC sun.gc.collector.0.invocations
YGCT sun.gc.collector.0.time/sun.os.hrt.frequency
FGC sun.gc.collector.1.invocations
FGCT sun.gc.collector.1.time/sun.os.hrt.frequency
CGC sun.gc.collector.2.invocations
CGCT sun.gc.collector.2.time/sun.os.hrt.frequency
GCT (sun.gc.collector.0.time + sun.gc.collector.1.time + sun.gc.collector.2.time)/sun.os.hrt.frequency

gc 堆的统计

G1MonitoringSupport::G1MonitoringSupport(G1CollectedHeap* g1h) :
        _g1h(g1h){
    _young_collection_counters = new G1YoungGenerationCounters(this, "young");
    const char* young_collection_name_space = _young_collection_counters->name_space();
    //  name "generation.0.space.2"
    _from_counters = new HSpaceCounters(young_collection_name_space,
            "s0", 1 /* ordinal */,
            pad_capacity(0) /* max_capacity */,
            pad_capacity(0) /* init_capacity */); 
    //  name "generation.0.space.1"
    _to_counters = new HSpaceCounters(young_collection_name_space,
            "s1", 2 /* ordinal */,
            pad_capacity(overall_reserved()) /* max_capacity */,
            pad_capacity(survivor_space_committed()) /* init_capacity */);
    //  name "generation.0.space.0"
    _eden_counters = new HSpaceCounters(young_collection_name_space,
            "eden", 0 /* ordinal */,
            pad_capacity(overall_reserved()) /* max_capacity */,
            pad_capacity(eden_space_committed()) /* init_capacity */);
    
    
    _old_collection_counters = new G1OldGenerationCounters(this, "old");
    _old_space_counters = new HSpaceCounters(_old_collection_counters->name_space(),
            "space", 0 /* ordinal */,
            pad_capacity(overall_reserved()) /* max_capacity */,
            pad_capacity(old_space_committed()) /* init_capacity */);
}
    

young space 注册

G1YoungGenerationCounters::G1YoungGenerationCounters(G1MonitoringSupport* g1mm,
                                                     const char* name)
  : G1GenerationCounters(g1mm, name, 0 /* ordinal */, 3 /* spaces */,
               G1MonitoringSupport::pad_capacity(0, 3) /* min_capacity */,
               G1MonitoringSupport::pad_capacity(g1mm->young_gen_max(), 3),
               G1MonitoringSupport::pad_capacity(0, 3) /* curr_capacity */) {
}
G1GenerationCounters::G1GenerationCounters(G1MonitoringSupport* g1mm,
                                           const char* name,
                                           int ordinal, int spaces,
                                           size_t min_capacity,
                                           size_t max_capacity,
                                           size_t curr_capacity)
  : GenerationCounters(name, ordinal, spaces, min_capacity,
                       max_capacity, curr_capacity), _g1mm(g1mm) {
}
GenerationCounters::GenerationCounters(const char* name,
                                       int ordinal, int spaces,
                                       size_t min_capacity, size_t max_capacity,
                                       size_t curr_capacity)
              : _virtual_space(NULL) {
    initialize(name, ordinal, spaces, min_capacity, max_capacity, curr_capacity);
}
void GenerationCounters::initialize(const char* name, int ordinal, int spaces,
                                    size_t min_capacity, size_t max_capacity,
                                    size_t curr_capacity) {
    // ordinal 的值是 0
    const char* cns = PerfDataManager::name_space("generation", ordinal);
    cname = PerfDataManager::counter_name(_name_space, "spaces");
    PerfDataManager::create_constant(SUN_GC, cname, PerfData::U_None, spaces, CHECK);
    
    cname = PerfDataManager::counter_name(_name_space, "capacity");
    _current_size = PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Bytes,
                                       curr_capacity, CHECK);
}

old space 注册

G1OldGenerationCounters::G1OldGenerationCounters(G1MonitoringSupport* g1mm,
                                                 const char* name)
  : G1GenerationCounters(g1mm, name, 1 /* ordinal */, 1 /* spaces */,
               G1MonitoringSupport::pad_capacity(0) /* min_capacity */,
               G1MonitoringSupport::pad_capacity(g1mm->old_gen_max()),
               G1MonitoringSupport::pad_capacity(0) /* curr_capacity */) {
}
G1GenerationCounters::G1GenerationCounters(G1MonitoringSupport* g1mm,
                                           const char* name,
                                           int ordinal, int spaces,
                                           size_t min_capacity,
                                           size_t max_capacity,
                                           size_t curr_capacity)
  : GenerationCounters(name, ordinal, spaces, min_capacity,
                       max_capacity, curr_capacity), _g1mm(g1mm) {
}

metaspace 统计

void MetaspaceCounters::initialize_performance_counters() {
    size_t min_capacity = 0;
    _perf_counters = new MetaspacePerfCounters("metaspace", min_capacity,
                                               capacity(), max_capacity(), used());
}

压缩类指针空间

void CompressedClassSpaceCounters::initialize_performance_counters() {
    const char* ns = "compressedclassspace";
    if (UseCompressedClassPointers) {
        size_t min_capacity = 0;
        _perf_counters = new MetaspacePerfCounters(ns, min_capacity, capacity(),
                                                 max_capacity(), used());
    } else {
        _perf_counters = new MetaspacePerfCounters(ns, 0, 0, 0, 0);
    }
}

collector 统计

G1MonitoringSupport::G1MonitoringSupport(G1CollectedHeap* g1h) :
          _g1h(g1h){
    // YGC
    _incremental_collection_counters =
        new CollectorCounters("G1 incremental collections", 0);
    // FGC
    _full_collection_counters =
        new CollectorCounters("G1 stop-the-world full collections", 1);
    // CGC
    _conc_collection_counters =
        new CollectorCounters("G1 stop-the-world phases", 2);
}
CollectorCounters::CollectorCounters(const char* name, int ordinal) {
    const char* cns = PerfDataManager::name_space("collector", ordinal);
    strcpy(_name_space, cns);
    
    cname = PerfDataManager::counter_name(_name_space, "invocations");
    _invocations = PerfDataManager::create_counter(SUN_GC, cname,
                                                   PerfData::U_Events, CHECK);
    // time 的单位应该是
    cname = PerfDataManager::counter_name(_name_space, "time");
    _time = PerfDataManager::create_counter(SUN_GC, cname, PerfData::U_Ticks,
                                            CHECK);
}

frequency

void StatSampler::create_misc_perfdata() {
    // 频率的单位是纳秒,1 s = 10^9 ns
    PerfDataManager::create_constant(SUN_OS, "hrt.frequency",
                                   PerfData::U_Hertz, os::elapsed_frequency(),
                                   CHECK);
}
const jlong NANOSECS_PER_SEC      = CONST64(1000000000);
jlong os::elapsed_frequency() {
    // 10的9次方
    return NANOSECS_PER_SEC; // nanosecond resolution
}

heap space 相关计算

结构体

class G1MonitoringSupport : public CHeapObj<mtGC> {
    size_t _eden_committed;
    size_t _eden_used;
    size_t _survivor_committed;
    size_t _survivor_used;
    size_t _old_committed;
    size_t _old_used;
    
    size_t eden_space_committed() {
        return _eden_committed;
    }
    size_t eden_space_used() {
        return _eden_used;
    }
    size_t survivor_space_committed()   { 
        return _survivor_committed;   
    }
    size_t survivor_space_used()        { 
        return _survivor_used;        
    }
    size_t old_space_committed()        {
        return _old_committed;        
    }
    size_t old_space_used()             {
        return _old_used;             
    }
};
class G1CollectedHeap : public CollectedHeap {
    size_t _summary_bytes_used;
};

size_t G1CollectedHeap::used_unlocked() const {
    return _summary_bytes_used;
}

capacity

void G1MonitoringSupport::update_sizes() {
    recalculate_sizes();
    
    eden_counters()->update_capacity(pad_capacity(eden_space_committed()));
    eden_counters()->update_used(eden_space_used());
    
    to_counters()->update_capacity(pad_capacity(survivor_space_committed()));
    to_counters()->update_used(survivor_space_used());
    
    old_space_counters()->update_capacity(pad_capacity(old_space_committed()));
    old_space_counters()->update_used(old_space_used());
    
}

void G1MonitoringSupport::recalculate_sizes() {
    // young 的当前 region 数量
    uint young_list_length = _g1h->young_regions_count();
    // survivor 的当前 region 数量
    uint survivor_list_length = _g1h->survivor_regions_count();
    // eden 的当前 region 数量
    uint eden_list_length = young_list_length - survivor_list_length;
    // young 的最大数量
    uint young_list_max_length = _g1h->g1_policy()->young_list_max_length();
    // eden 的最大数量 = young max - survivor size
    uint eden_list_max_length = young_list_max_length - survivor_list_length;
    
    _eden_used = (size_t) eden_list_length * HeapRegion::GrainBytes;
    _survivor_used = (size_t) survivor_list_length * HeapRegion::GrainBytes;
    // java 堆总使用空间
    _overall_used = _g1h->used_unlocked();
    // old used = 参数1 - 参数2 = 总使用空间 - eden used - survivor used
    _old_used = subtract_up_to_zero(_overall_used, _eden_used + _survivor_used);
    // survivor 的容量,因为 g1 的 survivor 没有实际的容量,只有虚拟的上限。所以默认认为 used == capacity
    _survivor_committed = _survivor_used;
    // 暂时设置为 old used
    _old_committed = HeapRegion::align_up_to_region_byte_size(_old_used);
    
    // g1 的当前容量(非物理的上限,除非 -Xms == -Xmx)
    _overall_committed = _g1h->capacity();
    size_t committed = _overall_committed;
    // 目前的这个 committed 就是 all_commited - (survivor used + old used)
    committed -= _survivor_committed + _old_committed;
    // eden 的 capacity
    _eden_committed = (size_t) eden_list_max_length * HeapRegion::GrainBytes;
    _eden_committed = MIN2(_eden_committed, committed);
    
    committed -= _eden_committed;
    // 多出来的空间,分给 old
    _old_committed += committed;
    // 年轻代的整体容量 = eden capacity + survivor used
    _young_gen_committed = _eden_committed + _survivor_committed;
    _eden_used = MIN2(_eden_used, _eden_committed);
}

used_unlocked

java 堆的总使用空间

size_t G1CollectedHeap::used_unlocked() const {
    return _summary_bytes_used;
}
void G1CollectedHeap::decrease_used(size_t bytes) {
    _summary_bytes_used -= bytes;
}
void G1CollectedHeap::set_used(size_t bytes) {
    _summary_bytes_used = bytes;
}
void G1CollectedHeap::increase_used(size_t bytes) {
    _summary_bytes_used += bytes;
}

used

class G1MonitoringSupport : public CHeapObj<mtGC> {
    size_t _eden_committed;
    size_t _eden_used;
    size_t eden_space_used()            {
        return _eden_used;            
    }
};

void G1MonitoringSupport::update_eden_size() {
    recalculate_eden_size();
    // 更新 eden used
    eden_counters()->update_used(eden_space_used());
}

void G1MonitoringSupport::recalculate_eden_size() {
    // 当前年轻代占用的 region 数量
    uint young_region_num = _g1h->young_regions_count();
    // _young_region_num: 旧值
    if (young_region_num > _young_region_num) {
        // 增长的数量
        uint diff = young_region_num - _young_region_num;
        // 实际的大小(不考虑 region 内的实际对象占用,默认认为整个 region 都占用了)
        _eden_used += (size_t) diff * HeapRegion::GrainBytes;
        // _eden_committed: 是 eden 区的容量 
        _eden_used = MIN2(_eden_used, _eden_committed);
        // 记录 young_region 大小
        _young_region_num = young_region_num;
    }
}

常用指令

打印 gc 的具体值

$ jstat -gc 23216
S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT    CGC    CGCT     GCT
0.0   7168.0  0.0   7168.0 131072.0 92160.0  3704832.0   785227.9  357448.0 343382.1 45388.0 40007.2    743    6.652   0      0.000  276     6.103   12.755

打印 gc 的百分比和 gc 的原因

$ jstat -gccause 23216
S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT    CGC    CGCT     GCT    LGCC                 GCC
0.00 100.00  14.96  21.17  96.19  88.31    763    6.851     0    0.000   290    6.373   13.224 G1 Evacuation Pause  No GC

打印 gc 的百分比

$ jstat -gcutil 23216
S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT    CGC    CGCT     GCT
0.00 100.00  84.73  21.42  96.21  88.39    776    7.008     0    0.000   300    6.642   13.649

Clone this wiki locally