本文主要研究一下GarbageCollectionNotificationInfo

CompositeData
java.management/javax/management/openmbean/CompositeData.java

public interface CompositeData {

public CompositeType getCompositeType();

public Object get(String key) ;

public Object[] getAll(String[] keys) ;

public boolean containsKey(String key) ;

public boolean containsValue(Object value) ;

public Collection<?> values() ;

public boolean equals(Object obj) ;

public int hashCode() ;

public String toString() ;

}
CompositeData接口定义了getCompositeType、get、getAll、containsKey、containsValue、values、equals、hashCode、toString方法
CompositeDataView
java.management/javax/management/openmbean/CompositeDataView.java

public interface CompositeDataView {

public CompositeData toCompositeData(CompositeType ct);
}
CompositeDataView接口定义了toCompositeData方法,用于将数据转换为CompositeData
GcInfo
jdk.management/com/sun/management/GcInfo.java

public class GcInfo implements CompositeData, CompositeDataView {
private final long index;
private final long startTime;
private final long endTime;
private final Map<String, MemoryUsage> usageBeforeGc;
private final Map<String, MemoryUsage> usageAfterGc;
private final Object[] extAttributes;
private final CompositeData cdata;
private final GcInfoBuilder builder;

private GcInfo(GcInfoBuilder builder,
long index, long startTime, long endTime,
MemoryUsage[] muBeforeGc,
MemoryUsage[] muAfterGc,
Object[] extAttributes) {
this.builder = builder;
this.index = index;
this.startTime = startTime;
this.endTime = endTime;
String[] poolNames = builder.getPoolNames();
this.usageBeforeGc = new HashMap<String, MemoryUsage>(poolNames.length);
this.usageAfterGc = new HashMap<String, MemoryUsage>(poolNames.length);
for (int i = 0; i < poolNames.length; i++) {
this.usageBeforeGc.put(poolNames[i], muBeforeGc[i]);
this.usageAfterGc.put(poolNames[i], muAfterGc[i]);
}
this.extAttributes = extAttributes;
this.cdata = new GcInfoCompositeData(this, builder, extAttributes);
}

private GcInfo(CompositeData cd) {
GcInfoCompositeData.validateCompositeData(cd);

this.index = GcInfoCompositeData.getId(cd);
this.startTime = GcInfoCompositeData.getStartTime(cd);
this.endTime = GcInfoCompositeData.getEndTime(cd);
this.usageBeforeGc = GcInfoCompositeData.getMemoryUsageBeforeGc(cd);
this.usageAfterGc = GcInfoCompositeData.getMemoryUsageAfterGc(cd);
this.extAttributes = null;
this.builder = null;
this.cdata = cd;
}

public long getId() {
return index;
}

public long getStartTime() {
return startTime;
}

public long getEndTime() {
return endTime;
}

public long getDuration() {
return endTime - startTime;
}

public Map<String, MemoryUsage> getMemoryUsageBeforeGc() {
return Collections.unmodifiableMap(usageBeforeGc);
}

public Map<String, MemoryUsage> getMemoryUsageAfterGc() {
return Collections.unmodifiableMap(usageAfterGc);
}

public static GcInfo from(CompositeData cd) {
if (cd == null) {
return null;
}

if (cd instanceof GcInfoCompositeData) {
return ((GcInfoCompositeData) cd).getGcInfo();
} else {
return new GcInfo(cd);
}

}

// Implementation of the CompositeData interface
public boolean containsKey(String key) {
return cdata.containsKey(key);
}

public boolean containsValue(Object value) {
return cdata.containsValue(value);
}

public boolean equals(Object obj) {
return cdata.equals(obj);
}

public Object get(String key) {
return cdata.get(key);
}

public Object[] getAll(String[] keys) {
return cdata.getAll(keys);
}

public CompositeType getCompositeType() {
return cdata.getCompositeType();
}

public int hashCode() {
return cdata.hashCode();
}

public String toString() {
return cdata.toString();
}

public Collection<?> values() {
return cdata.values();
}

public CompositeData toCompositeData(CompositeType ct) {
return cdata;
}
}
GcInfo实现了CompositeData及CompositeDataView接口,它主要有index、startTime、endTime、usageBeforeGc、usageAfterGc、extAttributes、cdata这几个属性
GarbageCollectionNotificationInfo
jdk.management/com/sun/management/GarbageCollectionNotificationInfo.java

public class GarbageCollectionNotificationInfo implements CompositeDataView {

private final String gcName;
private final String gcAction;
private final String gcCause;
private final GcInfo gcInfo;
private final CompositeData cdata;

public static final String GARBAGE_COLLECTION_NOTIFICATION =
"com.sun.management.gc.notification";

public GarbageCollectionNotificationInfo(String gcName,
String gcAction,
String gcCause,
GcInfo gcInfo) {
if (gcName == null) {
throw new NullPointerException("Null gcName");
}
if (gcAction == null) {
throw new NullPointerException("Null gcAction");
}
if (gcCause == null) {
throw new NullPointerException("Null gcCause");
}
this.gcName = gcName;
this.gcAction = gcAction;
this.gcCause = gcCause;
this.gcInfo = gcInfo;
this.cdata = new GarbageCollectionNotifInfoCompositeData(this);
}

GarbageCollectionNotificationInfo(CompositeData cd) {
GarbageCollectionNotifInfoCompositeData.validateCompositeData(cd);

this.gcName = GarbageCollectionNotifInfoCompositeData.getGcName(cd);
this.gcAction = GarbageCollectionNotifInfoCompositeData.getGcAction(cd);
this.gcCause = GarbageCollectionNotifInfoCompositeData.getGcCause(cd);
this.gcInfo = GarbageCollectionNotifInfoCompositeData.getGcInfo(cd);
this.cdata = cd;
}

public String getGcName() {
return gcName;
}

public String getGcAction() {
return gcAction;
}

public String getGcCause() {
return gcCause;
}

public GcInfo getGcInfo() {
return gcInfo;
}

public static GarbageCollectionNotificationInfo from(CompositeData cd) {
if (cd == null) {
return null;
}

if (cd instanceof GarbageCollectionNotifInfoCompositeData) {
return ((GarbageCollectionNotifInfoCompositeData) cd).getGarbageCollectionNotifInfo();
} else {
return new GarbageCollectionNotificationInfo(cd);
}
}

public CompositeData toCompositeData(CompositeType ct) {
return cdata;
}

}
GarbageCollectionNotificationInfo实现了CompositeDataView接口的toCompositeData方法,它主要有gcName、gcAction、gcCause、gcInfo、cdata这几个属性,toCompositeData返回的是cdata
实例
G1
G1 Young Generation
{
"gcAction": "end of minor GC",
"gcCause": "G1 Evacuation Pause",
"gcInfo": {
"compositeType": {
"className": "javax.management.openmbean.CompositeData",
"description": "CompositeType for GC www.huarenyl.cn info for G1 Young Generation",
"typeName": "sun.management.G1 Young Generation.GcInfoCompositeType"
},
"duration": 29,
"endTime": 18593,
"id": 38,
"memoryUsageAfterGc": {
"CodeHeap 'profiled nmethods'": {
"committed": 8847360,
"init": 2555904,
"max": 122912768,
"used": 8816000
},
"G1 Old Gen": {
"committed": 88080384,
"init": 17825792,
"max": 524288000,
"used": 62842880
},
"CodeHeap 'non-profiled nmethods'": {
"committed": 2555904,
"init": 2555904,
"max": 122916864,
"used": 1793408
},
"G1 Survivor Space": {
"committed": 2097152,
"init": 0,
"max": -1,
"used": 2097152
},
"Compressed Class Space": {
"committed": 6160384,
"init": 0,
"max": 1073741824,
"used": 5670976
},
"Metaspace": {
"committed": 49676288,
"init": 0,
"max": -1,
"used": 48404152
},
"G1 Eden Space": {
"committed": 13631488,
"init": 15728640,
"max": -1,
"used": 0
},
"CodeHeap 'non-nmethods'www.myptvip8.com": {
"committed": 2555904,
"init": 2555904,
"max": 5828608,
"used": 1199360
}
},
"memoryUsageBeforeGc": {
"CodeHeap 'profiled nmethods'": {
"committed": 8847360,
"init": 2555904,
"max": 122912768,
"used": 8816000
},
"G1 Old Gen": {
"committed": 89128960,
"init": 17825792,
"max": 524288000,
"used": 59823984
},
"CodeHeap 'non-profiled nmethods'": {
"committed": 2555904,
"init": 2555904,
"max": 122916864,
"used": 1793408
},
"G1 Survivor Space": {
"committed": 1048576,
"init": 0,
"max": -1,
"used": 1048576
},
"Compressed Class Space": {
"committed": 6160384,
"init": 0,
"max": 1073741824,
"used": 5670976
},
"Metaspace": {
"committed": 49676288,
"init": 0,
"max": -1,
"used": 48404152
},
"G1 Eden Space": {
"committed": 13631488,
"init": 15728640,
"max": -1,
"used": 12582912
},
"CodeHeap 'non-nmethods'www.feifanyule.cn": {
"committed": 2555904,
"init": 2555904,
"max": 5828608,
"used": 1199360
}
},
"startTime": 18564
},
"gcName": "G1 Young Generation"
}
G1 Old Generation
{
"gcAction": "end of major GC",
"gcCause": "G1 Evacuation Pause",
"gcInfo": {
"compositeType": {
"className": "javax.management.openmbean.CompositeData",
"description": "CompositeType for GC info for G1 Old Generation",
"typeName": "sun.management.G1 Old Generation.GcInfoCompositeType"
},
"duration": 127,
"endTime": 14107,
"id": 2,
"memoryUsageAfterGc": {
"CodeHeap 'profiled nmethods'": {
"committed": 9043968,
"init": 2555904,
"max": 122912768,
"used": 9008768
},
"G1 Old Gen": {
"committed": 50331648,
"init": 15728640,
"max": 67108864,
"used": 50126800
},
"CodeHeap 'non-profiled nmethods'": {
"committed": 2555904,
"init": 2555904,
"max": 122916864,
"used": 1814144
},
"G1 Survivor Space"www.honghgjpt.com: {
"committed": 0,
"init": 0,
"max": -1,
"used": 0
},
"Compressed Class Space": {
"committed": 6160384,
"init": 0,
"max": 1073741824,
"used": 5631528
},
"Metaspace": {
"committed": 49676288,
"init": 0,
"max": -1,
"used": 48270608
},
"G1 Eden Space": {
"committed": 16777216,
"init": 17825792,
"max": -1,
"used": 0
},
"CodeHeap 'non-nmethods'": {
"committed": 2555904,
"init": 2555904,
"max": 5828608,
"used": 1197696
}
},
"memoryUsageBeforeGc"www.365soke.com: {
"CodeHeap 'profiled nmethods'": {
"committed": 9043968,
"init": 2555904,
"max": 122912768,
"used": 9008768
},
"G1 Old Gen": {
"committed": 65011712,
"init": 15728640,
"max": 67108864,
"used": 64820264
},
"CodeHeap 'non-profiled nmethods'": {
"committed": 2555904,
"init": 2555904,
"max": 122916864,
"used": 1814144
},
"G1 Survivor Space": {
"committed": 1048576,
"init": 0,
"max": -1,
"used": 1048576
},
"Compressed Class Space": {
"committed": 6160384,
"init": 0,
"max": 1073741824,
"used": 5664624
},
"Metaspace": {
"committed": 49676288,
"init": 0,
"max": -1,
"used": 48375680
},
"G1 Eden Space": {
"committed": 1048576,
"init": 17825792,
"max": -1,
"used": 0
},
"CodeHeap 'non-nmethods'www.yunshengpt.com": {
"committed": 2555904,
"init": 2555904,
"max": 5828608,
"used": 1197696
}
},
"startTime": 13980
},
"gcName": "G1 Old Generation"
}
ZGC
ZGC Warmup
{
"gcAction": "end of major GC",
"gcCause": "Warmup",
"gcInfo": {
"compositeType": {
"className": "javax.management.openmbean.CompositeData",
"description": "CompositeType for GC info for ZGC",
"typeName": "sun.management.ZGC.GcInfoCompositeType"
},
"duration": 6562,
"endTime": 28676,
"id": 2,
"memoryUsageAfterGc": {
"ZHeap": {
"committed": 2145386496,
"init": 2147483648,
"max": 2147483648,
"used": 656408576
},
"CodeHeap 'profiled nmethods'": {
"committed": 9830400,
"init": 2555904,
"max": 122912768,
"used": 9767424
},
"CodeHeap 'non-profiled nmethods'": {
"committed": 2555904,
"init": 2555904,
"max": 122916864,
"used": 2076288
},
"Metaspace": {
"committed": 49020928,
"init": 0,
"max": -1,
"used": 47278192
},
"CodeHeap 'non-nmethods'www.078881.cn/": {
"committed": 2555904,
"init": 2555904,
"max": 5828608,
"used": 1190528
}
},
"memoryUsageBeforeGc": {
"ZHeap": {
"committed": 2145386496,
"init": 2147483648,
"max": 2147483648,
"used": 444596224
},
"CodeHeap 'profiled nmethods'": {
"committed": 9568256,
"init": 2555904,
"max": 122912768,
"used": 9546880
},
"CodeHeap 'non-profiled nmethods'": {
"committed": 2555904,
"init": 2555904,
"max": 122916864,
"used": 2051968
},
"Metaspace": {
"committed": 49020928,
"init": 0,
"max": -1,
"used": 47895808
},
"CodeHeap 'non-nmethods'": {
"committed": 2555904,
"init": 2555904,
"max": 5828608,
"used": 1184768
}
},
"startTime": 22114
},
"gcName": "ZGC"
}
ZGC Allocation Rate
{
"gcAction": "end of major GC",
"gcCause": "Allocation Rate",
"gcInfo": {
"compositeType": {
"className": "javax.management.openmbean.CompositeData",
"description": "CompositeType for GC info for ZGC",
"typeName": "sun.management.ZGC.GcInfoCompositeType"
},
"duration": 1028,
"endTime": 288728,
"id": 3,
"memoryUsageAfterGc": {
"ZHeap": {
"committed": 2145386496,
"init": 2147483648,
"max": 2147483648,
"used": 278921216
},
"CodeHeap 'profiled nmethods'": {
"committed": 11206656,
"init": 2555904,
"max": 122912768,
"used": 11141248
},
"CodeHeap 'non-profiled nmethods'": {
"committed": 2555904,
"init": 2555904,
"max": 122916864,
"used": 2198656
},
"Metaspace": {
"committed": 49283072,
"init": 0,
"max": -1,
"used": 48287392
},
"CodeHeap 'non-nmethods'": {
"committed": 2555904,
"init": 2555904,
"max": 5828608,
"used": 1184768
}
},
"memoryUsageBeforeGc": {
"ZHeap": {
"committed": 2145386496,
"init": 2147483648,
"max": 2147483648,
"used": 236978176
},
"CodeHeap 'profiled nmethods'": {
"committed": 11010048,
"init": 2555904,
"max": 122912768,
"used": 11005568
},
"CodeHeap 'non-profiled nmethods'": {
"committed": 2555904,
"init": 2555904,
"max": 122916864,
"used": 2197632
},
"Metaspace": {
"committed": 48758784,
"init": 0,
"max": -1,
"used": 47908112
},
"CodeHeap 'non-nmethods'": {
"committed": 2555904,
"init": 2555904,
"max": 5828608,
"used": 1184128
}
},
"startTime": 287700
},
"gcName": "ZGC"
}
Shenandoah
Shenandoah Cycles
{
"gcAction": "end of GC cycle",
"gcCause": "No GC",
"gcInfo": {
"compositeType": {
"className": "javax.management.openmbean.CompositeData",
"description": "CompositeType for GC info for Shenandoah Cycles",
"typeName": "sun.management.Shenandoah Cycles.GcInfoCompositeType"
},
"duration": 18,
"endTime": 1201551,
"id": 5,
"memoryUsageAfterGc": {
"CodeHeap 'non-profiled nmethods'": {
"committed": 9371648,
"init": 2555904,
"max": 244105216,
"used": 9310592
},
"Shenandoah": {
"committed": 54525952,
"init": 4294967296,
"max": 4294967296,
"used": 34113640
},
"Compressed Class Space": {
"committed": 5373952,
"init": 0,
"max": 1073741824,
"used": 4724464
},
"Metaspace": {
"committed": 37355520,
"init": 0,
"max": -1,
"used": 35581640
},
"CodeHeap 'non-nmethods'": {
"committed": 2555904,
"init": 2555904,
"max": 7553024,
"used": 1209216
}
},
"memoryUsageBeforeGc": {
"CodeHeap 'non-profiled nmethods'": {
"committed": 9306112,
"init": 2555904,
"max": 244105216,
"used": 9300096
},
"Shenandoah": {
"committed": 54525952,
"init": 4294967296,
"max": 4294967296,
"used": 42502592
},
"Compressed Class Space": {
"committed": 5373952,
"init": 0,
"max": 1073741824,
"used": 4724464
},
"Metaspace": {
"committed": 37355520,
"init": 0,
"max": -1,
"used": 35581640
},
"CodeHeap 'non-nmethods'": {
"committed": 2555904,
"init": 2555904,
"max": 7553024,
"used": 1209216
}
},
"startTime": 1201533
},
"gcName": "Shenandoah Cycles"
}
Shenandoah Pauses
{
"gcAction": "end of GC pause",
"gcCause": "No GC",
"gcInfo": {
"compositeType": {
"className": "javax.management.openmbean.CompositeData",
"description": "CompositeType for GC info for Shenandoah Pauses",
"typeName": "sun.management.Shenandoah Pauses.GcInfoCompositeType"
},
"duration": 1,
"endTime": 1201551,
"id": 20,
"memoryUsageAfterGc": {
"CodeHeap 'non-profiled nmethods'": {
"committed": 0,
"init": 0,
"max": 0,
"used": 0
},
"Shenandoah": {
"committed": 0,
"init": 0,
"max": 0,
"used": 0
},
"Compressed Class Space": {
"committed": 0,
"init": 0,
"max": 0,
"used": 0
},
"Metaspace": {
"committed": 0,
"init": 0,
"max": 0,
"used": 0
},
"CodeHeap 'non-nmethods'": {
"committed": 0,
"init": 0,
"max": 0,
"used": 0
}
},
"memoryUsageBeforeGc": {
"CodeHeap 'non-profiled nmethods'": {
"committed": 0,
"init": 0,
"max": 0,
"used": 0
},
"Shenandoah": {
"committed": 0,
"init": 0,
"max": 0,
"used": 0
},
"Compressed Class Space": {
"committed": 0,
"init": 0,
"max": 0,
"used": 0
},
"Metaspace": {
"committed": 0,
"init": 0,
"max": 0,
"used": 0
},
"CodeHeap 'non-nmethods'": {
"committed": 0,
"init": 0,
"max": 0,
"used": 0
}
},
"startTime": 1201550
},
"gcName": "Shenandoah Pauses"
}
小结
GarbageCollectorMXBean在完成一个次垃圾收集的action的时候会发射一个A garbage collection notification,它返回的是GarbageCollectionNotificationInfo
GarbageCollectionNotificationInfo实现了CompositeDataView接口的toCompositeData方法,它主要有gcName、gcAction、gcCause、gcInfo、cdata这几个属性,toCompositeData返回的是cdata;GcInfo实现了CompositeData及CompositeDataView接口,它主要有index、startTime、endTime、usageBeforeGc、usageAfterGc、extAttributes、cdata这几个属性
可以发现无论是使用G1 GC、ZGC还是Shenandoah GC,都能从对应的GarbageCollectionNotificationInfo获取相关信息,只是不同的垃圾收集器除了gcName不一样外,它们的usageBeforeGc及usageAfterGc(Map<String, MemoryUsage>)中的key也不尽相同
doc
GarbageCollectionNotificationInfo

聊聊GarbageCollectionNotificationInfo的更多相关文章

  1. 聊聊Unity项目管理的那些事:Git-flow和Unity

    0x00 前言 目前所在的团队实行敏捷开发已经有了一段时间了.敏捷开发中重要的一个话题便是如何对项目进行恰当的版本管理.项目从最初使用svn到之后的Git One Track策略再到现在的GitFlo ...

  2. Mono为何能跨平台?聊聊CIL(MSIL)

    前言: 其实小匹夫在U3D的开发中一直对U3D的跨平台能力很好奇.到底是什么原理使得U3D可以跨平台呢?后来发现了Mono的作用,并进一步了解到了CIL的存在.所以,作为一个对Unity3D跨平台能力 ...

  3. fir.im Weekly - 聊聊 Google 开发者大会

    中国互联网的三大错觉:索尼倒闭,诺基亚崛起,谷歌重返中国.12月8日,2016 Google 开发者大会正式发布了Google Developers 中国网站 ,包含了Android Develope ...

  4. 聊聊asp.net中Web Api的使用

    扯淡 随着app应用的崛起,后端服务开发的也越来越多,除了很多优秀的nodejs框架之外,微软当然也会在这个方面提供更便捷的开发方式.这是微软一贯的作风,如果从开发的便捷性来说的话微软是当之无愧的老大 ...

  5. 没有神话,聊聊decimal的“障眼法”

    0x00 前言 在上一篇文章<妥协与取舍,解构C#中的小数运算>的留言区域有很多朋友都不约而同的说道了C#中的decimal类型.事实上之前的那篇文章的立意主要在于聊聊使用二进制的计算机是 ...

  6. 聊聊 C 语言中的 sizeof 运算

    聊聊 sizeof 运算 在这两次的课上,同学们已经学到了数组了.下面几节课,应该就会学习到指针.这个速度的确是很快的. 对于同学们来说,暂时应该也有些概念理解起来可能会比较的吃力. 先说一个概念叫内 ...

  7. 聊聊 Apache 开源协议

    摘要 用一句话概括 Apache License 就是,你可以用这代码,但是如果开源你必须保留我写的声明:你可以改我的代码,但是如果开源你必须写清楚你改了哪些:你可以加新的协议要求,但不能与我所 公布 ...

  8. 【原】聊聊js代码异常监控

    在平时的工作,js报错是比较常见的一个情景,尤其是有一些错误可能我们在本地测试的时候测试不出来,当发布到线上之后才可以发现,如果抢救及时,那还好,假如很晚才发 现,那就可能造成很大的损失了.如果我们前 ...

  9. Replication的犄角旮旯(三)--聊聊@bitmap

    <Replication的犄角旮旯>系列导读 Replication的犄角旮旯(一)--变更订阅端表名的应用场景 Replication的犄角旮旯(二)--寻找订阅端丢失的记录 Repli ...

随机推荐

  1. SDK安装详解以及adb的来源

    首先,下载Android SDK Tools,翻过墙的朋友可以去Google Android的官网上下载(http://developer.android.com/sdk/index.html) 选择 ...

  2. shell脚本--初识CGI

    CGI按照百度百科的定义,如下: CGI 是Web 服务器运行时外部程序的规范,按CGI 编写的程序可以扩展服务器功能.CGI 应用程序能与浏览器进行交互,还可通过数据库API 与数据库服务器等外部数 ...

  3. WIN下修改host文件并立即生效

    怎样修改WIN7下的host文件_百度经验https://jingyan.baidu.com/article/9faa72317903f1473c28cb01.html hosts立即生效的方法 - ...

  4. Jenkins+Docker自动化集成环境搭

    关于Docker Docker 简介 Docker现在是Github社区最火的项目之一,Docker是个容器,或许你听过lxc,你可能知道Tomcat这个Web容器,容器是什么概念,意会就好.问个问题 ...

  5. # 【Python3练习题 007】 有一对兔子,从出生后第3个月起每个月都生一对兔子, # 小兔子长到第三个月后每个月又生一对兔子, # 假如兔子都不死,问每个月的兔子总数为多少?

    # 有一对兔子,从出生后第3个月起每个月都生一对兔子,# 小兔子长到第三个月后每个月又生一对兔子, # 假如兔子都不死,问每个月的兔子总数为多少?这题反正我自己是算不出来.网上说是经典的“斐波纳契数列 ...

  6. 手机移动端input date placehoder不显示

    要解决这个问题,我们可以伪造一个placehoder,通过css跟js来解决这个问题. 为什么要用js的原因是因为当你选择了时间之后,placehoder的文字没有清除掉,所以我们就需要把这个伪造的p ...

  7. Spark源码编译,官网学习

    这里以spark-1.6.0版本为例 官网网址   http://spark.apache.org/docs/1.6.0/building-spark.html#building-with-build ...

  8. C# Note31: 如何使用Visual Studio做单元测试

    待更! 使用Visual Studio 2013进行单元测试--初级篇 带你玩转Visual Studio——单元测试(C++例)

  9. python爬虫之初始scrapy

    简介: Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架. 可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中. 其最初是为了 页面抓取 (更确切来说, 网络抓取 )所设 ...

  10. Navicat软件安装

    Navicat_10.1.7永久注册码 NAVH-WK6A-DMVK-DKW3