首页 文章 精选 留言 我的

精选列表

搜索[云真机],共10000篇文章
优秀的个人博客,低调大师

【死磕JVM】用Arthas排查JVM内存 真爽!我从小用到大

Arthas是啥 当我们系统遇到JVM或者内存溢出等问题的时候,如何对我们的程序进行有效的监控和排查,就发现了几个比较常用的工具,比如JDK自带的 jconsole、jvisualvm还有一个最好用的工具——jprofiler,但是这个是收费的,或者除了很有钱的公司,一般很少人会用这个,还有一个就是我们今天的主角——Arthas ,为什么今天会重点讲这个呢? 官网地址:http://arthas.gitee.io/GitHub地址:https://github.com/alibaba/arthas/ Arthas 是Alibaba开源的Java诊断工具,采用命令行交互模式,提供了较为丰富的功能,主要还是他是免费里面的算是好用且功能比较强大的一个JVM排查的插件,在了解这个利器之后,发现还是挺好用的,而且支持的功能也比较全面,那么Arthas到底可以为我们做哪些事情呢? 提供性能看板,包括线程、cpu、内存等信息,并且会定时的刷新。 根据各种条件查看线程快照。找出cpu占用率最高的n个线程 输出jvm的各种信息,如gc算法、jdk版本、ClassPath等 遇到问题无法在线上 debug,热部署加日志直接替换 查看某个类的静态属性,也可以通过ognl语法执行一些语句 查看已加载的类的详细信息,这个类从哪个jar包加载的,查看类的方法的信息 dump 类的字节码到指定目录 直接反编译指定的类 快速定位应用的热点,生成火焰图 可以监控到JVM的实时运行状态 以前,你碰到这些问题,解决的办法大多是,修改代码,重新上线。但是在大公司里,上线的流程是非常繁琐的,如果为了多加一行日志而重新发布版本,无疑是非常折腾人的。但是阿里巴巴开源的Arthas有了更为优雅的线上调试方法。 Arthas 支持JDK6,同时可以在 Linux/Mac/Windows上运行,自动Tab 补全功能,更方便我们定位问题和诊断 下载地址:https://arthas.gitee.io/download.html你可以下载zip的包我下载的是arthas-packaging-3.5.0-bin.zip或者通过命令去下载 wget https://alibaba.github.io/arthas/arthas-boot.jar 使用手册 1. 快速启动 当我们下载好之后,我们直接通过命令启动就可以java -jar arthas-boot.jar,但是在此之前我们需要通过检测的代码来挂靠到Arthas上面 import java.math.BigDecimal; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class FullGCTest { //模拟银行卡的类 private static class CardInfo { //小农的银行卡信息记录 BigDecimal price = new BigDecimal(10000000.0); String name = "牧小农"; int age = 18; Date birthdate = new Date(); public void m() {} } //线程池 定时线程池 //50个,然后设置 拒绝策略 private static ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(50, new ThreadPoolExecutor.DiscardOldestPolicy()); public static void main(String[] args) throws Exception { executor.setMaximumPoolSize(50); for (;;){ modelFit(); Thread.sleep(100); } } /** * 对银行卡进行风险评估 */ private static void modelFit(){ List<CardInfo> taskList = getAllCardInfo(); //拿出每一个信息出来 taskList.forEach(info -> { // do something executor.scheduleWithFixedDelay(() -> { //调用M方法 info.m(); }, 2, 3, TimeUnit.SECONDS); }); } private static List<CardInfo> getAllCardInfo(){ List<CardInfo> taskList = new ArrayList<>(); //每次查询100张卡出来 for (int i = 0; i < 100; i++) { CardInfo ci = new CardInfo(); taskList.add(ci); } return taskList; } } 这个是上篇文章讲述的案例,感兴趣的可以了解一下。 首先我们需要使用javac 命令将Java文件进行编译javac FullGCTest.java进行编译,然后打印GC日志,进行风险监控打印GC日志:java -Xms200M -Xmx200M -XX:+PrintGC FullGCTest Arthas启动命令:java -jar arthas-boot.jar 我们就看到了我们刚才启动的FullGCTest的应用程序,我们输入编号 1 回车,这样我们就把Arthas挂靠到我们的程序上,接下来我们只需要做对应的命令操作就可以了 命令详情文档:https://arthas.aliyun.com/doc/commands.html 2. 功能列表 命令 详细说明 jvm 查看当前JVM信息 thread 查看当前JVM的线程堆栈信息 watch 方法执行数据观测 dashboard 当前系统的实时数据面板 trace 方法内部调用路径,并输出方法路径上的每个节点上耗时 stack 输出当前方法被调用的调用路径 tt 方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测 vmoption 查看,更新JVM已加载的类信息 sc 查看JVM已加载的类信息 sm 查看已加载类的方法信息 jad 反编译指定已加载类的源码 classloader 查看classloader的继承树,urls,类加载信息 heapdump 类似jmap命令的heap dump 功能 jvm OPERATING-SYSTEM:系统相关参数 THREAD相关: COUNT : JVM当前活跃的线程数 DAEMON-COUNT : JVM当前活跃的守护线程数 PEAK-COUNT: 从JVM启动开始曾经活着的最大线程数 STARTED-COUNT: 从JVM启动开始总共启动过的线程次数 DEADLOCK-COUNT: JVM当前死锁的线程数 MEMORY FILE-DESCRIPTOR(文件描述符相关): MAX-FILE-DESCRIPTOR-COUNT:JVM进程最大可以打开的文件描述符数 OPEN-FILE-DESCRIPTOR-COUNT:JVM当前打开的文件描述符数 thread 命令 参数说明: 命令 详细说明 id 线程id [n:] 指定最忙的前N个线程并打印堆栈 [b] 找出当前阻塞其他线程的线程 [i] 指定cpu使用率统计的采样间隔,单位为毫秒,默认值为200 [--all] 显示所有匹配的线程 打印当前最忙的N个线程并打印堆栈 thread -n 3 thread 查看所有线程 thread 17: 显示指定线程的运行堆栈 thread -i: 指定采样时间间隔 thread -i 1000 : 统计最近1000ms内的线程CPU时间。thread -n 3 -i 1000 : 列出1000ms内最忙的3个线程栈 dashboard 命令 运行程序时,会显示当前程序的实时信息,如qps, rt, 错误数, 线程池信息等等 数据说明: ID: Java级别的线程ID NAME: 线程名 GROUP: 线程组名 PRIORITY: 线程优先级, 1~10之间的数字,越大表示优先级越高 STATE: 线程的状态CPU%: 线程的cpu使用率。比如采样间隔1000ms,某个线程的增量cpu时间为100ms,则cpu使用率=100/1000=10% DELTA_TIME: 上次采样之后线程运行增量CPU时间,数据格式为秒 TIME: 线程运行总CPU时间,数据格式为分:秒 INTERRUPTED: 线程当前的中断位状态 DAEMON: 是否是daemon线程 参数说明: 参数名称 详细说明 id 刷新实时数据的时间间隔 (ms),默认5000ms [n:] 刷新实时数据的次数 sc 命令 查看JVM已加载的类信息,通过SC我们可以看到我们这个类的详细信息,包括是从哪个jar包读取的,他是不是接口/枚举类等,甚至包括他是从哪个类加载器加载的。 参数说明: 参数名称 详细说明 class-pattern 类名表达式匹配 method-pattern 方法名表达式匹配 [d] 输出当前类的详细信息,包括这个类所加载的原始文件来源、类的声明、加载的ClassLoader等详细信息。如果一个类被多个ClassLoader所加载,则会出现多次 [E] 开启正则表达式匹配,默认为通配符匹配 sc -d *CardInfo: 打印类的详细信息 sc -d -f *CardInfo:打印类的Fiedld信息 heapdump + jhat分析 heapdump:类似于jmap命令 创建到指定文件夹下: [arthas@365564]$ heapdump /usr/local/mxn/dump.hprof Dumping heap to /usr/local/mxn/dump.hprof ... Heap dump file created 创建成功后,我们就可以在指定文件夹下看到对应的dump文件,然后使用命令jhat dump.hprof,生成文件,成功后我们就可以通过IP+端口进行访问了 访问: 然后我们就可以通过IP+端口去访问它了,里面有个他的other,我们拉到最底下,找 Show instance counts for all classes (including platform) 从下面我们可以分析出来哪个类包含的对象最多,分析出来哪个类产生的对象 这个里面最强大的功能还是叫做 Execute Object Query Language (OQL) query,这个里面可以显示有哪些对象,对象有多少个字节和引用,可以观察到哪个对象产生了问题,如下图所示,显示所有String对应的对象 搜索点进去之后我们还能看到这个对象到底占用了多少个字节,有多少个引用指向了这个Object,这个OQL的语法也是很灵活,我们可以使用where条件去过滤 jad jad:反编译某个类,或者反编译某个类的某个方法,动态代理生成类的问题定位 第三方的类(观察代码) 版本问题(确定自己最新提交的版本是不是被使用) 有人可能会问这个有啥用,源码我不是自己就知道吗?因为有时我们经常会不确定线上或者测试环境的包是否是我们修改过的,这时候就可以通过jad反编译来看下,是否是最新的代码 redafine redafine:热替换,动态更新代码,不用重启jvm目前有些限制条件:只能改方法实现(方法已经运行完成),不能改方法名, 不能改属性 m() -> mm() 比如我们在线上环境有个class确认有问题,想要重新替换,一般情况下只能停掉服务器重新发布,在普通的小公司这样是可以的,但是在大规模公司京东淘宝这样的是不能停的,因为整个流程是非常复杂的,那怎么办呢?大家可以看到下面的案例 首先我们新建一个测试案例: public class T{ public static void main(String[] args) throws Exception{ for(;;){ System.in.read(); new TT().m(); } } } public class TT{ public void m(){ System.out.println(2); } } 使用命令javac *.java,编译成class文件,然后运行 T 文件 [root@VM-0-7-centos t]# java T a 2 2 当我们输入a的时候打印2,但是我们上线以后才发现,我们需要输出的1,这个是如果要从本地更改要重新发布上线,为了这一个修改,明显是不值当的,但是如果我们用 redafine 热部署就可以帮助我们直接替换,不用重新发布jvm 然后我们将 T 这个程序挂靠到 Arthas 上面去 然后我们直接修改 TT.java 程序 vi TT.java,将里面打印2的值修改成1 public class TT{ public void m(){ System.out.println(1); } } 然后编译执行 ```javac TT.java ```` 在回到我们挂靠的Arthas 上面执行 redefine /usr/local/mxn/fuccGc/t/TT.class [arthas@398842]$ redefine /usr/local/mxn/fuccGc/t/TT.class redefine success, size: 1, classes: TT 执行成功大家可以看到我们在没有重新启动的情况下成功替换了class文件 watch watch:方法执行的数据观测,可以通过watch指令,来监控某个类,监控后,运行下你的功能,复现下场景,arthas会提供给你具体的出参和入参,帮助你排查故障 trace 输出方法调用路径,并输出耗时,这个指令对于优化代码非常的有用,可以看出具体每个方法执行的时间,如果是for循环等重复语句,还能看出n次循环中的最大耗时,最小耗时,和平均耗时,完美! tt 在我们对某个方法开启tt后,会记录每一次调用(我们可以设置最大监控次数)的入参和返回参数,并能对这些不同时间下调进行观测 [arthas@405136]$ tt -t FullGCTest modelFit 命令参数解析-ttt 命令有很多个主参数,-t 就是其中之一。这个参数的表明希望记录下类 *Test 的 print 方法的每次执行情况。-n 3当你执行一个调用量不高的方法时可能你还能有足够的时间用 CTRL+C 中断 tt 命令记录的过程,但如果遇到调用量非常大的方法,瞬间就能将你的 JVM 内存撑爆。 此时你可以通过 -n 参数指定你需要记录的次数,当达到记录次数时 Arthas 会主动中断tt命令的记录过程,避免人工操作无法停止的情况。 ognl表达式 ognl表达式 OGNL特殊用法请参考:https://github.com/alibaba/arthas/issues/71OGNL表达式官方指南:https://commons.apache.org/proper/commons-ognl/language-guide.html 调用静态函数:ognl '@java.lang.System@out.println("hello")'获取静态类的静态字段:ognl '@FullGCTest@random' Arthas还支持Web Console,详见:https://alibaba.github.io/arthas/web-console.html 总结 Arthas是一个线上Debug神器,相比于其他工具,Arthas有着比较全面的功能,上手也比较容易,对于刚开始入门的小伙伴也是可以轻松掌握的,对于文中有不懂或者有问题的小伙伴,大家可以在下面留言评论。 原创不易,希望大家多多捧场,记得一键三连!!! 我是牧小农,怕什么真理无穷,进一步有进一步的欢喜,大家加油!

优秀的个人博客,低调大师

真牛逼!我司用了7年的分布式锁方案...

点击上方“方志朋”,选择“设为星标” 回复”666“获取新整理的面试文章 提到数据一致性、操作原子性,诸如此类的一些与并发有关的词汇时不知道你第一时间会联想到什么呢?我相信大多数人可能会想到“锁”,为什么是锁呢,这个我不多说,大家心里应该都明白。在单体应用时代,我们使用jvm提供的锁就可以很好的工作,但是到了分布式应用时代,jvm提供的锁就行不通了,那么势必要借助一些跨jvm的临界资源来支持锁的相关语义,比如redis,zookeeper等。 步入正题 我今天就来分享下我司基于redis来实现的分布式锁,2013年投入使用,也算是久经沙场。但是也存在一些设计上的缺陷,这个我后面也会提到,希望大家秉着互相学习的态度文明交流,别一上来就说这不行那不行,还是那句话“适合自己的才是最好的”。 加锁过程分析 image 我第一次读代码的时候,有这么几个疑惑: Q1:为什么不使用 SET key value [expiration EX seconds|PX milliseconds] [NX|XX] 这个指令来实现key的自动过期呢,反而放到应用代码判断key是否过期? A1:我们的分布式锁开发的时候SET命令还不支持NX、PX,所以才想出这种办法来实现key过期,NX、PX在2.6.12以后开始支持; Q2:已经判断了当前key对应的时间戳已经过期了,为什么还要使用getset再获取一次呢,直接使用set指令覆盖不可以吗? A2:这里其实牵扯到并发的一些事情,如果直接使用set,那有可能多个客户端会同时获取到锁,如果使用getset然后判断旧值是否过期就不会有这个问题,设想一下如下场景: C1加锁成功,不巧的是,这时C1意外的奔溃了,自然就不会释放锁; C2,C3尝试加锁,这时key已存在,所以C2,C3去判断key是否已过期,这里假设key已经过期了,所以C2,C3使用set指令去设置值,那两个都会加锁成功,这就闯大祸了;如果使用getset指令,然后判断下返回值是否过期就可以避免这种问题,假如C2跑的快,那C3判断返回的时间戳已经过期,自然就加锁失败; 释放锁过程分析 image Q1:为什么释放锁时还需要判断key是否过期呢,直接del不是性能更高吗? A1:考虑这样一种场景: C1获取锁成功,开始执行自己的操作,不幸的是C1这时被阻塞了; C2这时来获取锁,由于C1被阻塞了很长时间,所以key对应的value已经过期了,这时C2通过getset加锁成功; C1尘封了太久终于被再次唤醒,对于释放锁这件事它可是认真的,伴随着一波del操作,悲剧即将发生; C3来获取锁,好家伙,居然一下就成功了,接着就是一波操作猛如虎,接着就是一堆的客诉过来了; 为什么会这样呢?回想C1被唤醒以后的事情,居然敢直接del,C2活都没干完呢,锁就被C1给释放了,这时C3来直接就加锁成功,所以为了安全起见C3释放锁时得分成两步:1.判断value是否已经过期 2.如果已过期直接忽略,如果没过期就执行del。这样就真的安全了吗?安全了吗?安全了吗?假如第一步和第二步之间相隔了很久是不是也会出现锁被其他人释放的问题呢?是吧?是的!有没有别的解决办法呢?听说借助lua就可以解决这个问题了,感兴趣的直接给你传送过去可好。 正视自己的缺点 Q1:Redis锁的过期时间小于业务的执行时间该如何续期? A1:这个暂时没有实现,据说有一个叫Redisson的家伙解决了这个问题,我们也有部分业务在使用,未来有可能会切换到Redisson。 Q2:怎么实现的高可用? A2:我们采用Failover机制,初始化redis锁的时候会维护一个redis连接池,加锁或者释放锁的时候采用多写的方式来保障一致性,如果某个节点不可用的时候会自动切换到其他节点,但是这种机制可能会导致多个客户端同时获取到锁的情况,考虑这种情况: C1去redis1加锁,加锁成功后会写到redis2,redis3; C2也去redis1加锁,但是此时C2到redis1的网络出现问题,这时C2切换到redis2去加锁,由于第一步中的redis多写并不是原子的,所有就有可能导致C2也获取锁成功; 针对这种情况,目前有些业务方是通过数据库唯一索引的方式来规避的,未来会修复这个bug,具体方案目前还没有。 来源 |https://urlify.cn/iQJ3qa 热门内容: 15000 字的 SQL 语句大全 为什么阿里巴巴要禁用 Executors 创建线程池? Spring的Controller是单例还是多例?怎么保证并发的安全 一款直击痛点的优秀http框架,让我超高效率完成了和第三方接口的对接 Spring Boot 中的 RestTemplate不好用?试试 Retrofit ! 为什么建议大家使用 Linux 开发?爽(外加七个感叹号) 最近面试BAT,整理一份面试资料《Java面试BAT通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。获取方式:点“在看”,关注公众号并回复666领取,更多内容陆续奉上。 明天见(。・ω・。)ノ 本文分享自微信公众号 - 方志朋(walkingstory)。如有侵权,请联系 support@oschina.cn 删除。本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

优秀的个人博客,低调大师

全球售价比较后 真崩溃

【大咖・来了 第7期】10月24日晚8点观看《智能导购对话机器人实践》 9月14日下午15点01,首批iPhone XS、iPhone XS Max将正式开启预订。相比去年来说,今年新机***的改变就是,苹果继续在产品组合上调整,为的是能够让售价继续变高,对于很多用户来说,想要承担新iPhone已经变的越来越困难了。 现在有外媒就汇总了首批预订iPhone XS、iPhone XS Max在不同国家和地区的售价,先来说说中国国内,去年新机iPhone X售价是1224美元起,而今年已经涨至1269美元,而最贵的价格已经达到了1868美元。 新iPhone在美国的售价还是***的,去年iPhone X价格是999美元起,而今年依然是这个价格,最贵的512GB版本为1449美元。能够在价格上跟美国拼一拼的也就是日本和中国香港了。 日本去年iPhone X的售价是1008美元,而今年依然是1008美元,最贵的512GB版本价格是1473美元,至于中国香港嘛,去年iPhone X售价是1094美元起,而今年变成了1095美元,上涨了1美元,而最贵的为1592美元。 苹果新款iPhone在不同国家和地区的售价 新iPhone在欧洲的售价普遍偏高,比如意大利应该是目前512GB新iPhone最贵的了,居然达到了1971美元,折合人民币约13500元,而新iPhone的入门价格是1389美元。售价排在倒数第二高是波兰,而英国紧随其后。 中国国内售价横向对比后发现,虽然不是最贵的,但是也算是比较贵的了,真是很崩溃有木有啊。 那么苹果为什么要开始激进的走高价路线呢?原因有两点:***用户对iOS黏性依然很高,而实际上愿意为iPhone高价买单的用户并不少,而苹果手机均价走高全是靠iPhone X卖的好拉动,第二点就是,iPhone目前的销量已经进入瓶颈,既然换不来大的增长了,索性就来提高产品售价。 从苹果当前的节奏来看,他们会把超高端iPhone的路选给坚定的走下去。

优秀的个人博客,低调大师

单片机串口DMA收发方案

概述 网上各大教程对于串口的使用基本都是轮询发送、中断接收,极大浪费了MCU的性能,同时中断接收只能应付低速率的场景,对于要求波特率达到115200及以上的场景来说极其容易丢字节导致整个系统异常不稳定。 这篇文章我先以 RT-Thread 的串口方案作为切入点,然后给出我在STM32F1平台上基于RT-Thread Nano 实现的方案。 本方案实现的是非阻塞式的收发,不涉及 posix 的对接。posix 其实也是调用这些非阻塞接口,只不过还加了些对这些接口的返回判断再加入 wait_queue 来实现阻塞、唤醒,不详细展开来描写。 本方案的发送处理是应对的高并发场景,小内存MCU或者串口发送只在一个线程内的按你最简单的使用方式来。小内存的 MCU 接收推荐直接使用 DMA+IDLE 方式,怎么简单怎么来。而且不建议用串口框架,自己实现不仅可靠还可控!! RT-Thread 串口框架 RT-Thread 串口框架支持用户自己选择以下述方案打开串口: 轮询方式实际项目中基本是不用的;中断方式的发送会导致大量的中断,占用太多MCU资源,而且 RT-Thread 把中断发送做的跟轮询一样;中断方式的接收不仅会导致大量的中断而且对于高速通信需求的场景不适用。 DMA方式无论是发送还是接收都不需要CPU参与,解放了CPU,程序只需要对几个中断处理就行。 2.1. DMA发送 RT-Thread 串口框架中对于 DMA 发送使用的是 dataqueue 队列。 DMA 发送操作将要发送的数据指针及其长度保存在 dataqueue 成员中,发送时按照先进先出的规则从中取一块,将其保存的数据指针赋值给 DMA 内存地址。 这里不涉及数据拷贝,所以数据指针指向的内存区是局部的,用户需要在应用程序中通过设置信号量或其他方式来同步发送完成,否则将导致不安全的指针使用。多并发的情况下这种就会导致各种各样的问题了。 ..... 原文链接:https://club.rt-thread.org/ask/article/2594.html

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册