文章目录

  • 目标
  • Arthas
    • 简单使用
  • 其他
  • 其他诊断工具

目标

  • 了解Arthas 性能调优工具

    参考: Arthas - Java 线上问题定位处理的终极利器

    spring-boot 速成(3) actuator

    JVM内存区域详解(Eden Space、Survivor Space、Old Gen、Code Cache和Perm Gen)

    java性能监控利器Arthas

Arthas

是一个Java诊断工具,支持JDK 6+,支持Linux/Mac/Winodws

官方文档:https://alibaba.github.io/arthas/

国内文档地址:https://arthas.gitee.io/

安装包: https://arthas.gitee.io/arthas-boot.jar 国内

提供的测试项目: https://arthas.gitee.io/arthas/arthas-demo.jar

强烈建议根据官方文档的,在线教程(推荐) 学习了解。

idea 插件arthas-idea 汪小哥 这位大哥写的,简化一些复杂命令

简单使用

先执行要检测诊断的项目:参见 https://blog.csdn.net/u013735734/article/details/102930307 提供的代码段

import java.util.HashSet;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import lombok.extern.slf4j.Slf4j;/**
* <p>
* Arthas Demo
* 公众号:未读代码
*
* @Author niujinpeng
*/
@Slf4j
public class Arthas {private static HashSet hashSet = new HashSet();/** 线程池,大小1*/private static ExecutorService executorService = Executors.newFixedThreadPool(1);public static void main(String[] args) {// 模拟 CPU 过高,这里注释掉了,测试时可以打开// cpu();// 模拟线程阻塞thread();// 模拟线程死锁deadThread();// 不断的向 hashSet 集合增加数据addHashSetThread();}/*** 不断的向 hashSet 集合添加数据*/public static void addHashSetThread() {// 初始化常量new Thread(() -> {int count = 0;while (true) {try {hashSet.add("count" + count);Thread.sleep(10000);count++;} catch (InterruptedException e) {e.printStackTrace();}}}).start();}public static void cpu() {cpuHigh();cpuNormal();}/*** 极度消耗CPU的线程*/private static void cpuHigh() {Thread thread = new Thread(() -> {while (true) {log.info("cpu start 100");}});// 添加到线程executorService.submit(thread);}/*** 普通消耗CPU的线程*/private static void cpuNormal() {for (int i = 0; i < 10; i++) {new Thread(() -> {while (true) {log.info("cpu start");try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}}}).start();}}/*** 模拟线程阻塞,向已经满了的线程池提交线程*/private static void thread() {Thread thread = new Thread(() -> {while (true) {log.debug("thread start");try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}}});// 添加到线程executorService.submit(thread);}/*** 死锁*/private static void deadThread() {/** 创建资源 */Object resourceA = new Object();Object resourceB = new Object();// 创建线程Thread threadA = new Thread(() -> {synchronized (resourceA) {log.info(Thread.currentThread() + " get ResourceA");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}log.info(Thread.currentThread() + "waiting get resourceB");synchronized (resourceB) {log.info(Thread.currentThread() + " get resourceB");}}});Thread threadB = new Thread(() -> {synchronized (resourceB) {log.info(Thread.currentThread() + " get ResourceB");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}log.info(Thread.currentThread() + "waiting get resourceA");synchronized (resourceA) {log.info(Thread.currentThread() + " get resourceA");}}});threadA.start();threadB.start();}
}
  • 查看系统 和 Thread 的信息
#  启动arthas
$ java -jar .\arthas-boot.jar
# 启动后,会打印出来现在所有的java进程,选择要检测的java程序
# 看到arthas 图标出现后,就代表检测成功了# 全局检测
$ dashboard# 输出
ID       NAME                      GROUP             PRIORIT STATE    %CPU     TIME     INTERRU DAEMON
5        Attach Listener           system            5       RUNNABLE 0        0:0      false   true
17       DestroyJavaVM             main              5       RUNNABLE 0        0:0      false   false
3        Finalizer                 system            8       WAITING  0        0:0      false   true
6        Monitor Ctrl-Break        main              5       RUNNABLE 0        0:0      false   true
2        Reference Handler         system            10      WAITING  0        0:0      false   true
4        Signal Dispatcher         system            9       RUNNABLE 0        0:0      false   true
14       Thread-1                  main              5       BLOCKED  0        0:0      false   false
15       Thread-2                  main              5       BLOCKED  0        0:0      false   false
16       Thread-3                  main              5       TIMED_WA 0        0:0      false   false
29       Timer-for-arthas-dashboar system            10      RUNNABLE 0        0:0      false   true
22       arthas-shell-server       system            5       TIMED_WA 0        0:0      false   true
28       as-command-execute-daemon system            10      TIMED_WA 0        0:0      false   true
19       job-timeout               system            5       TIMED_WA 0        0:0      false   true
Memory                   used   total   max    usage   GC
heap                     41M    243M    3607M  1.15%   gc.ps_scavenge.count      2
ps_eden_space            29M    63M     1331M  2.23%   gc.ps_scavenge.time(ms)   12
ps_survivor_space        10M    10M     10M    99.85%  gc.ps_marksweep.count     0
ps_old_gen               1M     169M    2705M  0.05%   gc.ps_marksweep.time(ms)  0
nonheap                  22M    23M     -1     96.87%
code_cache               4M     4M      240M   1.93%
Runtime
os.name                                              Windows 10
os.version                                           10.0
java.version                                         1.8.0_111
java.home                                            D:\bcinstall\jdk\jre
systemload.average                                   -1.00
processors                                           12
uptime                                               736sheap : 堆
ps_eden_space : 新生代-伊甸园
ps_survivor_space :  新生代中-幸存者
ps_old_gen : 老年代
nonheap : 非堆内存保存虚拟机自己的静态(reflective)数据,例如类(class)和方法(method)对象。Java虚拟机共享这些类数据。这个区域被分割为只读的和只写的。
code_cache : 代码缓存区HotSpot Java虚拟机包括一个用于编译和保存本地代码(native code)的内存,叫做“代码缓存区”(code cache)。gc.ps_scavenge.count  : 垃圾回收次数
gc.ps_scavenge.time :垃圾回收消耗时间
gc.ps_marksweep.count : 标记-清除算法的次数
gc.ps_marksweep.time :标记-清除算法的消耗时间STATE 状态RUNNABLE 运行中TIMED_WAITIN 调用了以下方法的线程会进入TIMED_WAITING:Thread#sleep()Object#wait() 并加了超时参数Thread#join() 并加了超时参数LockSupport#parkNanos()LockSupport#parkUntil()WAITING 当线程调用以下方法时会进入WAITING状态:Object#wait() 而且不加超时参数Thread#join() 而且不加超时参数LockSupport#park()BLOCKED 阻塞,等待锁# 查看所有的线程
$ thread# 查看某个线程 thread Id
$ thread 14
# 输出
"Thread-1" Id=14 BLOCKED on java.lang.Object@37ea7c84 owned by "Thread-2" Id=15at fun.gengzi.thread.Arthas.lambda$deadThread$4(Arthas.java:125)-  blocked on java.lang.Object@37ea7c84-  locked java.lang.Object@74a2f34eat fun.gengzi.thread.Arthas$$Lambda$2/511833308.run(Unknown Source)at java.lang.Thread.run(Thread.java:745)Affect(row-cnt:0) cost in 11 ms.提示 Thread-1 被 thread-2 拥有的  java.lang.Object@37ea7c84 阻塞在 fun.gengzi.thread.Arthas.lambda$deadThread$4(Arthas.java:125) 发生在 java.lang.Object@37ea7c84 上被阻塞锁定了java.lang.Object@74a2f34e# 查看死锁信息
$ thread -b
# 输出
"Thread-1" Id=14 BLOCKED on java.lang.Object@37ea7c84 owned by "Thread-2" Id=15at fun.gengzi.thread.Arthas.lambda$deadThread$4(Arthas.java:125)-  blocked on java.lang.Object@37ea7c84-  locked java.lang.Object@74a2f34e <---- but blocks 1 other threads!(阻塞了一个其他线程)at fun.gengzi.thread.Arthas$$Lambda$2/511833308.run(Unknown Source)at java.lang.Thread.run(Thread.java:745)Affect(row-cnt:0) cost in 11 ms.# 排列出 CPU 使用率 Top N 的线程
$  thread -n 5
# 输出
[arthas@44800]$ thread -n 5
"Reference Handler" Id=2 cpuUsage=0% WAITING on java.lang.ref.Reference$Lock@6915cdaeat java.lang.Object.wait(Native Method)-  waiting on java.lang.ref.Reference$Lock@6915cdaeat java.lang.Object.wait(Object.java:502)at java.lang.ref.Reference.tryHandlePending(Reference.java:191)at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)"Finalizer" Id=3 cpuUsage=0% WAITING on java.lang.ref.ReferenceQueue$Lock@d7f8ed9at java.lang.Object.wait(Native Method)-  waiting on java.lang.ref.ReferenceQueue$Lock@d7f8ed9at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)"Signal Dispatcher" Id=4 cpuUsage=0% RUNNABLE
"Attach Listener" Id=5 cpuUsage=0% RUNNABLE"job-timeout" Id=19 cpuUsage=0% TIMED_WAITING on java.util.TaskQueue@2013be8at java.lang.Object.wait(Native Method)-  waiting on java.util.TaskQueue@2013be8at java.util.TimerThread.mainLoop(Timer.java:552)at java.util.TimerThread.run(Timer.java:505)Affect(row-cnt:0) cost in 113 ms.
  • 统计方法耗时 trace 和 monitor

    这里需要启动另一个工程,https://github.com/gengzi/GsjBlog 这里使用的是这个工程,调用了一个 登陆的接口,包:club.gsjglob.action.UserController 方法 login ,在浏览器端请求,来查看这个方法的一些执行情况。(可以使用自己的web工程做测试)

# trace 跟踪统计方法耗时
$ trace club.gsjglob.action.UserController  login
# 输出
[arthas@241]$ trace club.gsjglob.action.UserController  login
Press Q or Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 194 ms.
`---ts=2020-05-15 13:33:25;thread_name=http-nio-8080-exec-2;id=12;is_daemon=true;priority=5;TCCL=org.apache.catalina.loader.ParallelWebappClassLoader@648b39c`---[23.17502ms] club.gsjglob.action.UserController:login()+---[0.02849ms] club.gsjglob.dto.User:getIsadmin() #60+---[14.269801ms] club.gsjglob.service.IUserService:login() #63`---[0.017177ms] club.gsjglob.domain.GsjUser:getUserid() #64可以看到执行到的各个方法耗时
[14.269801ms] club.gsjglob.service.IUserService:login() #63 这个耗时比较长
可以继续查找这个耗时长的方法,直到确定那个方法比较耗时,这里的方法耗时,主要体现在连接查询mysql数据# monitor 命令监控统计方法的执行情况
# 每5秒统计一次 club.gsjglob.action.UserController 类的 login 方法执行情况。
$ monitor -c 5 club.gsjglob.action.UserController  login
# 输出 每五秒钟执行一次timestamp            class                               method  total  success  fail  avg-rt(ms)  fail-rate
--------------------------------------------------------------------------------------------------------------                           2020-05-15 13:40:40  club.gsjglob.action.UserController  login   14     14       0     9.60        0.00%     
  • 观察方法的入参出参信息
# watch -h 查看一下具体的参数
# watch 查看入参和出参
$ watch club.gsjglob.action.UserController login '{params[0],returnObj}'
# 输出
[arthas@241]$ watch club.gsjglob.action.UserController login '{params[0],returnObj}'
Press Q or Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 47 ms.
ts=2020-05-15 13:53:56; [cost=8.543274ms] result=@ArrayList[@User[club.gsjglob.dto.User@2abe0213],@GsjUser[club.gsjglob.domain.GsjUser@531ded4c],
]可以看到
入参是 @User[club.gsjglob.dto.User@2abe0213],
出参是 @GsjUser[club.gsjglob.domain.GsjUser@531ded4c],# 查看入参和出参,出参的 一个属性 Userid
$ watch club.gsjglob.action.UserController login '{params[0],returnObj.getUserid()}'可以看出 对于入参和出参 可以调用他们可以调用的方法,来具体查看你需要查看的信息,更多用法,看 watch -h
  • 观察方法的调用路径
# stack 观察方法调用路径
$ stack club.gsjglob.action.UserController login
# 输出
[arthas@241]$ stack club.gsjglob.action.UserController login
Press Q or Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 50 ms.
ts=2020-05-15 14:08:06;thread_name=http-nio-8080-exec-6;id=16;is_daemon=true;priority=5;TCCL=org.apache.catalina.loader.ParallelWebappClassLoader@648b39c@sun.reflect.GeneratedMethodAccessor209.invoke()at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:777)at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:706)at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
  • 方法调用时空隧道
# tt 命令方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测 。
$ tt -t   club.gsjglob.action.UserController login[arthas@241]$ tt -t   club.gsjglob.action.UserController login
Press Q or Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 93 ms.INDEX    TIMESTAMP            COST(ms)   IS-RET  IS-EXP   OBJECT          CLASS                           METHOD
------------------------------------------------------------------------------------------------------------------------------------------1000     2020-05-15 14:10:06  8.938093   true    false    0x123d07bf      UserController                  login                         1001     2020-05-15 14:10:06  4.306842   true    false    0x123d07bf      UserController                  login                         1002     2020-05-15 14:10:06  1.866464   true    false    0x123d07bf      UserController                  login                         1003     2020-05-15 14:10:06  1.850198   true    false    0x123d07bf      UserController                  login                         1004     2020-05-15 14:10:07  2.277625   true    false    0x123d07bf      UserController                  login                         1005     2020-05-15 14:10:07  1.754767   true    false    0x123d07bf      UserController                  login                         1006     2020-05-15 14:10:07  5.819472   true    false    0x123d07bf      UserController                  login                         1007     2020-05-15 14:10:07  1.744265   true    false    0x123d07bf      UserController                  login                         1008     2020-05-15 14:10:07  4.954611   true    false    0x123d07bf      UserController                  login                         1009     2020-05-15 14:10:07  2.020023   true    false    0x123d07bf      UserController                  login                         1010     2020-05-15 14:10:07  1.79095    true    false    0x123d07bf      UserController                  login                         1011     2020-05-15 14:10:11  1.66948    true    false    0x123d07bf      UserController                  login                         1012     2020-05-15 14:10:13  26.496748  false   true     0x123d07bf      UserController                  login                         1013     2020-05-15 14:10:17  5.981863   false   true     0x123d07bf      UserController                  login                         1014     2020-05-15 14:10:17  6.267794   false   true     0x123d07bf      UserController                  login                         1015     2020-05-15 14:10:17  4.178886   false   true     0x123d07bf      UserController                  login                         1016     2020-05-15 14:10:17  7.940246   false   true     0x123d07bf      UserController                  login                         1017     2020-05-15 14:10:18  10.339824  false   true     0x123d07bf      UserController                  login                         1018     2020-05-15 14:10:18  8.588795   false   true     0x123d07bf      UserController                  login       IS-EXP = true  表示有异常# 查看记录的方法调用信息: tt -l
$ tt -l# 查看某一个调用记录的详细信息  tt -i INDEX$  tt -i 1018
# 输出
[arthas@241]$ tt -i 1018INDEX            1018                                                                                                  GMT-CREATE       2020-05-15 14:10:18                                                                                                    COST(ms)         8.588795                                                                                                               OBJECT           0x123d07bf                                                                                                             CLASS            club.gsjglob.action.UserController                                                                                     METHOD           login                                                                                                                  IS-RETURN        false                                                                                                                  IS-EXCEPTION     true                                                                                                                   PARAMETERS[0]    @User[                                                                                                                 adminname=@String[gsjadmin],                                                                                       adminpasswd=@String[gsjadmin],                                                                                     isadmin=@String[admin],                                                                                            ]                                                                                                                      PARAMETERS[1]    @RequestFacade[                                                                                                        request=@Request[org.apache.catalina.connector.Request@49a22c5e],                                                  sm=@StringManager[org.apache.tomcat.util.res.StringManager@4d9da1b2],                                              ]                                                                                                                      PARAMETERS[2]    @ResponseFacade[                                                                                                       sm=@StringManager[org.apache.tomcat.util.res.StringManager@4d9da1b2],                                              response=@Response[org.apache.catalina.connector.Response@6145ce6e],                                               ]                                                                                                                      THROW-EXCEPTION  redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool                        at redis.clients.util.Pool.getResource(Pool.java:50)                                                                  at redis.clients.jedis.JedisPool.getResource(JedisPool.java:86)                                                       at club.gsjglob.tools.JedisClientPool.set(JedisClientPool.java:15)                                                    at club.gsjglob.action.UserController.login(UserController.java:76)                                                   at sun.reflect.GeneratedMethodAccessor209.invoke(Unknown Source)                                                      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)   这里输出了调用这个方法的参数 和 出现的异常信息,发现是 redis 相关的异常。# 重新发起调用某一个记录  tt -i INDEX -p
$ tt -i 1018 -p

其他

jps jvm提供的,可以查看当前所有的java进程

其他诊断工具

  • Bistoury

github地址: bistoury

Bistoury是去哪儿网的java应用生产问题诊断工具,提供了一站式的问题诊断方案

Bistoury在保留arthas和vjtools的所有功能之外,还提供了更加丰富的功能

动态对方法添加监控

在线debug功能

线程级cpu使用率监控

  • vjtools

    唯品会开源的诊断工具

    github地址:vjtools

    视频:《VJTools如何利用佛性技术玩转JVM》

    文档:《入门科普,围绕JVM的各种外挂技术》

听说点赞关注的人,身体健康,一夜暴富,升职加薪迎娶白富美!!!

点我领取每日福利
微信公众号:耿子blog
GitHub地址:gengzi

阿里性能调优工具Arthas相关推荐

  1. JVM性能调优(4)——性能调优工具

    目录 一.JDK工具1.JDK工具2.利用 jps 找出进程3.利用 jstat 查看VM统计信息4.利用 jmap 查看对象分布情况5.利用 jstack 分析线程栈 二.Linux 命令行工具1. ...

  2. Java应用性能调优工具介绍及实践

    一.背景 (1).随着微服务架构的逐渐推广,一个大型的单个应用程序被拆分为数个微服务系统,这为研发人员的本地调试跟踪带来困难 (2).在微服务架构中,由于业务的复杂性,常常一个业务流程涉及好数个微服务 ...

  3. jvm性能调优工具之 jmap使用详解

    本文来说下jvm性能调优工具之 jmap使用详解 文章目录 概述 jmap用法 示例一:no option 示例二:heap 示例三:histo[:live] 示例四:clstats 示例五:fina ...

  4. mysql配置优化ya_mysql性能调优工具之mytop

    Mysql性能调优工具之mytop的安装和使用 1.mytop的下载地址 2.首先安装mytop必要的组件. yum -y install perl-DBD-MySQL perl-DBIperl-Te ...

  5. JVM性能调优监控工具专题一:JVM自带性能调优工具(jps,jstack,jmap,jhat,jstat,hprof)...

    2019独角兽企业重金招聘Python工程师标准>>> 前提概要:         JDK本身提供了很多方便的JVM性能调优监控工具,除了集成式的VisualVM和jConsole外 ...

  6. java 性能 火焰图_性能调优工具-火焰图

    性能调优工具-火焰图 发布时间:2019-07-17 19:29, 浏览次数:402 前言 工具的进化一直是人类生产力进步的标志,合理使用工具能大大提高我们的工作效率,遇到问题时,合理使用工具更能加快 ...

  7. 【JVM 学习笔记 05】:JVM性能调优工具的使用和优化案例

    [JVM 学习笔记 05]:JVM性能调优工具的使用 1. 使用 jstat(命令行工具) 查看线上系统的JVM运行状况 1.1 常用命令 1.2 使用技巧 1.2.1 随着系统运行,每秒钟会在年轻代 ...

  8. 系统级性能调优工具Perf成功移植到龙芯处理器

    http://www.loongson.cn/news/company/304.html 程序优化主要包括算法优化.代码优化和系统级优化,Perf是Linux内核自带的系统级性能调优工具,2.6.31 ...

  9. HTML5应用性能调优工具WAPA – 安装篇

    转载: http://software.intel.com/node/506559 HTML5应用性能调优工具WAPA – 安装篇 Submitted by Dawei Cheng 程大伟... on ...

  10. HTML5应用性能调优工具WAPA – 使用篇

    转载: http://software.intel.com/zh-cn/blogs/2014/02/28/html5-wapa/?utm_campaign=CSDN&utm_source=in ...

最新文章

  1. 怎么在python下载网站内容-python从网站上下载东西
  2. 一个信道的数据传输速率为4kb/s,单向传播时延为30ms,如果使停止-等待协议的信道最大利用率达到80%,那么要求的数据帧长度至少为( )
  3. Hadoop框架:HDFS简介与Shell管理命令
  4. C#LeetCode刷题之#55-跳跃游戏(Jump Game)
  5. Android 呼吸灯流程分析
  6. python学习--交互式图形编程实例四
  7. js json数组_JaveScript对象篇和数组篇
  8. C#针对js escape解码
  9. linux版本搜狗,搜狗输入法linux版下载
  10. 使用后端解析地图.shp.prj文件得到GeoJson数据
  11. 深度装N卡LINUX驱动 性能怎么样,讲解Deepin 20开源Nouveau和闭源NVIDIA驱动,附装闭源N卡驱动的方法...
  12. 码农故事1——受惠寄居遇驴友 维艰窘境见人心
  13. 帝国cms 图集模型 php,帝国CMS教程图集字段的大图,小图,说明的调用
  14. 目标检测/图像分割 评价标准IOU/准确率及精确率
  15. 建行tendyronU盾 插入电脑突然不能自动跳转IE跳出登录密码框
  16. 互联网晚报 | 07月02日 星期六 | ​​​北京健康宝核酸检测天数计算规则调整;​上海鼓励用人单位吸纳失业3个月及以上人员...
  17. Web GIS多种方式发布动态地图服务及显示(2)
  18. LEFT JOIN左连接示例
  19. Python爬虫底层知识简介 - AI小白进阶之路
  20. 数据清洗--读行问题

热门文章

  1. 数据库系统概论-数据库系统阶段的特点
  2. 目标客户画像_目标客户和用户画像
  3. 手机上最好用的五笔输入法_最欠揍的手机输入法,用不好失业又失恋
  4. CANoe-第2个仿真工程-XVehicle—2Panel设计(原理,思路)
  5. Websphere9.0的安装
  6. android手机连不上wifi密码,修改wifi密码后手机连不上_修改wifi密码后手机不能上网-192路由网...
  7. 微型计算机主机的组成不包括______,微型计算机主机的主要组成部分是什么
  8. Tab表格thead头部固定(demo)
  9. 用elasticsearch和kibana 进行简单的实时数据报表分析
  10. rs232 485 ttl区别