技术学院

01-17
2018
我用Python玩小游戏“跳一跳”,瞬间称霸了朋友圈!0101
从前几天微信最新版本 6.6.1 的更新开始,微信小程序游戏“跳一跳”似乎在一夜之间风靡了朋友圈。它甚至比五六年前的飞机大战游戏都火爆,这种小游戏的火爆不仅仅是因为有魔性、有意思,更重要的是可以进行好友 PK!“跳一跳”的小游戏推出后,很多准备奋发向上的同学,这个假期的美好愿景被毁了。为了多跳几步,以及朋友圈的排名,大家在整个假期都是这样的:就这样跳啊跳...挤地铁跳,蹲马桶跳,乘电梯跳,静默的每 1 秒都不能浪费在办公室,还要时刻警觉后面...说好的工作呢...我控制不住我自己啊!可是很多人费尽心思跳了一下午也没超过 100 分但排行榜里四分之三的人都超过三位数了……真是扎心了……今天小编来告诉你,如何才能获取高分,如何才能占据朋友圈榜首?游戏攻略拿高分普通版本的高分秘籍是这样的:如果你每次都能挑到各自的正中间的话,可以 + 2 分,如果连着跳到中间会 + 4、+6、+8、+10……跳到污水井盖上面,停留 2 秒,等到下水道声音响起直接 + 5 分跳到魔方上面,停留 2 秒,等到魔方转正会直接 + 10 分跳到音乐盒上面,停留 2 秒,等到音乐响起会直接 + 30 分跳到便利店,停留 2 秒,等到便利店开门会直接 + 15 分以上是针对普通用户,但对咱们程序猿来说用这套太 Low 了,接下来要说的是如何从技术层面去实现高分:技术手段实现高分通过 Python 手段在 Github 上面已经有人用 Python 来玩跳一跳这个游戏了,想多少分就有多少分。GitHub 地址:https://github.com/wangshub/wechat_jump_game步骤:安卓手机打开 USB 调试,设置》开发者选项》USB 调试。电脑与手机 USB 线连接,确保执行 adb devices 可以找到设备 id。界面转至微信跳一跳游戏,点击开始游戏。运行 python wechat_junp_auto.py,如果手机界面显示 USB 授权,请点击确认。很有趣!简单点说就是:用电脑帮你玩微信跳一跳,全自动,不用手动。效果:这里梳理一份稍微完整一点的操作步骤,以 Mac 的为例,Win 的思路是一样的。另外,这里用的是安卓手机,iOS 也差不多,不过要下载一个 5.5GB 的 Xcode。1、下载程序,打开下面的链接,点右侧 clone or download,再点 download zip。2、解压 zip 文档,再把文件夹挪到桌面,打开文件夹,你会看到很多东东:3、打开 mac 系统自带的“终端”,这是一个命令行应用,win 用 cmd 就可以了吧。4、通过终端进入文件夹,命令行如下:~/Decktop/wechat_jump_game-master5、安装 pip,在终端输入 sudo easy_install pip 再回车,可能要输入密码。6、安装各种依赖程序,在终端输入 pip install -r requirements.txt 再回车,系统会自动安装。requirements.txt 就是文件夹里的一个 txt 文档,里面写着会自动安装哪些程序。pip 就是第 5 步安装的程序,如果没安装,pip install -r requirements.txt 将无法执行。7、安装 adb,打开下面的链接查看,有 3 种方法,建议用第二种,是英文,如果你不懂英文可以百度中文教程。https://stackoverflow.com/questions/31374085/installing-adb-on-mac-os-x8、打开安卓手机的设置 - 开发者选项 - USB 调试(如果没有开发者选项,可百度打开开发者选项的方法),用 USB 线连接手机和电脑,手机可能会弹出对话框,点同意。如果出现运行脚本后小人不跳的情况,请检查是否有打开“USB 调试(安全模式)”,记得顺便打开 USB 模拟点击。9、在终端输入 adb devices,如果看到下面这种信息,说明 adb 已正确安装,也说明电脑成功检测到手机。如果你系统是 Win10 或 Win8 可能需要先设置一下“禁用强制驱动程序签名”。不然会出现下面的“文件的哈希值不在指定目录中”安装不上 adb 驱动的问题,网上有教程请自行学习。10、打开微信跳一跳点开始,在终端输入 python wechat_jump_auto.py 点回车,游戏就会自动开始~ 请根据手机分辨率运行相应的 *.py 文件。注意:我跳了很多次,最后都会掉下盒子,暂时最多只能跳到 1800+ 分,不能一直跳下去。分辨率不同,配置文件也不一样,具体看 config 这个文件夹。别刷太高分,有人刷到 4000,结果分数被微信清零。实验结果:只要有耐心,你就是王者下面分析一下代码,Main 部分有一个 While 循环,只要你不终止,它会一直重复操作。Main部分代码里面主要调用的自定义函数有三个,还有一个 time.sleep 是为了延迟一下:pull_screenshot() #获取图像find_piece_and_board(im) #根据图像获取两个点的坐标值jump(math.sqrt((board_x - piece_x) ** 2 + (board_y - piece_y) ** 2))#根据两点距离和手机像素计算按压时间并 JUMPpull_screenshot()这个函数主要是利用 adb 来获取图像,这里顺便说一下“adb”,adb 是连接 Android 手机与 PC 端的桥梁,可以让用户在电脑上对手机进行全面的操作。借助 adb 工具,我们可以管理设备,还可以进行如安装软件、系统升级、运行 Shell 命令等等操作。如“pull”就是获取设备中的文件,想更多了解 ADB 请自行学习~find_piece_and_board()根据图像获取当前小人位置和落点的坐标系(piece_x, piece_y, board_x, board_y),这个是这个脚本中的核心部分。jump根据设定的“长按的时间系数”计算需要的按压时间,这个系数是根据手机分辨率推出来的,按压时间设定不小于 200ms,核心命令是 adb 的“input swipe”。“input swipe”模拟的是手指在屏幕上的滑动事件,如果两个点坐标不变化就成了长按了。代码中四个变量的设置是:“swipe_x1,swipe_y1,swipe_x2,swipe_y2 = 320,410,320,410”,所以是模拟的长按,其实滑动也是可以的。伪造 POST 请求刷分除了可以用 Python 实现高分,还有网友爆料还可以直接伪造 POST 请求刷分,直接改分数。昨日,V2EX 网站上一篇题为《微信跳一跳 可以直接更改分数, POST 请求没有校验… 》的文章获得大量曝光,帖中指出微信小程序存在漏洞,跳一跳小游戏可以直接改分数。用户朱鹏飞根据帖子的指引,发现甚至连微信小程序、小游戏的源代码都可以直接下载,只需要知道 appid 和版本号,就可以直接构造 URL 下载后缀为 wxapkg 的源码包,不需要任何验证。据微信公众号“小专栏平台”消息,截自 1 月 1 日 23:50,微信官方已经修复了这个漏洞。不过,据说一些老版本的微信还是可以抓包获取包地址。最后一个微信已经修复 Bug(部分版本没有修复),但只要利用好前面两个攻略,再配合对节奏的把握,登上朋友圈前几完全不在话下。话不多说,赶紧去玩吧!!!
01-17
2018
2018,怎么缓解大数据的尴尬0101
关于大数据,最近爆出的一个笑话:在电影业一次内部行业会议上,一位巨无霸级别的电影业发言人说:通过数据挖掘,我们发现不同观众的相关卖品偏好。比如《芳华》的观众比《战狼Ⅱ》观众消费了更多的热饮。这些都是之前我们不知道的,也是无法预测的。上面这样一个基于两部影片的观影数据分析得出来的结论,看似客观正确,实则因为模型不完善(缺少观影季节的考量)等原因,而闹出笑话。在近期,我们在给金融科技做盘点的时候,就发现大数据自身就是一个“尴尬”。我们找遍新闻,也没有发现这个词有什么特别值得说道的地方。只能靠着一点时政资料凑齐了这个关键词的盘点。2017年,大数据如此重要,却又如此没有料。大数据模型不完善,是因为根基不牢大数据一直不温不火,和他的发展缺陷有很大的关系。虽然大家极力看好它,但未能迎来行业的爆发。和一些做大数据的朋友聊天,他们甚至会很直白地吐槽自己家的数据模型。“那些所谓的数据模型之类的鬼东西,你只需瞄上一眼,就能头疼一整天。模型里的数据巨大无比,线索逻辑纷繁复杂。很多数据看似很重要却极其无聊,对结果判断毫无意义,食之无味弃之可惜,鸡肋一般的存在。”“说实在的,根本原因不在于技术的落后,而是整个行业的发展根基太浅,无法对数据的有效性进行勘误、归纳和合理解释。”“粗略地说,合理的大数据架构是,数据模型完善,能根据特定领域做出全面合理的数据精简,去掉无关数据和干扰数据,梳理出一条合理的客观建议,并根据数据分析师的主观判断和勘误,再总结出合理的结论,对相关行业做出准确的预判。”“现在呢?本来数据模型都存在这样和那样的漏洞,却还想着数据处理的完全自动化。”“而完全依靠客观数据,完成所谓的人工智能演算,那都是扯淡的事儿。”“刚才说的那个《芳华》和《战狼Ⅱ》的笑话其实就是一个看似客观,实则可笑的分析结论。”“这是因为,大家一说到大数据,就太拿数据想当然了。如果只靠着这点意识去做消费金融领域的数据分析,肯定有很多投资人被坑得底儿朝天!”“所以现在挣钱的还是那些靠着倒买倒卖用户资料的数据公司,一个数据包,加点水分,到处卖,收益无限。”“不过,最近似乎也没那么容易整了,因为官方越查越严,有些所谓的大数据公司搞不动了,怕是要凉了。”物联网或许是大数据公司的真正机会“除了行业经验的累积,还需要更多数据做线上支撑。”“当然,并不是说数据越多越好,而是说,线上的数据越丰富,越有利于我们组织有效数据。”“核心问题就在于,如何产生大量的有效数据。”“有效数据,简单了说,就某个领域,比如,消费金融领域的某一个小细分的消费品的相关数据,在合理组合和解构之后,对行业发展做出合理预判,对投资人预期负责的数据。否则,数据越大,负担越重,越成不了事儿。”积累经验到什么时候才算是个头呢?“或许要等到物联网时代的真正到来。”为什么?“物联网可以让更多的消费金融数据和物流数据线上化,个人消费信用信息也将进一步线上化,数据的归集和处理将更加高效和全面。”“不过,随着移动支付的快速发展,更多人的金融消费能力在线上就基本被呈现了出来,包括个人的消费习惯和个人征信信息都被线上化,而由此产生的物流信息、住房、贷款信息等都在逐步完成终极线上化,这些对大数据来说,都是极好的机会。”“大数据行业机会很大,但大数据是一个不稳定的行业,因为一切的数据都归结到机器里,而机器由人来掌控,相关的操作风险完全看自己的风险意识和人品。行业随时爆发大规模风险,运气好只影响数据安全,运气不好,很企业和个人的信用会破产。这会给行业,甚至整个社会带来巨大的灾难。”“因此,从业企业的相关准则需要进一步细化和规范,对人也需要有个职业操守方面的管制。”什么样的人怎么用数据,其目的和效果都是不一样的。这又和一个大数据相关的段子有点关系,正好段子开头,笑话结尾,也还算圆满。俺家钟点工说:“俺儿子又被老师训了。”俺问又咋啦?她说:学校请了个政法大学的教授来给孩子们讲课,说还是个名人呢,见天在电视上忽悠。他告诫孩子们不要打架,他说他统计过,打架斗殴死了的人百分之九十五以上都是先动手那个,然后问孩子们这是为什么?俺儿子说因为没死的说是死了的先动手的。
01-17
2018
解Bug之路:记一次JVM堆外内存泄露Bug的查找0101
前言JVM的堆外内存泄露的定位一直是个比较棘手的问题。此次的Bug查找从堆内内存的泄露反推出堆外内存,同时对物理内存的使用做了定量的分析,从而实锤了Bug的源头。笔者将此Bug分析的过程写成博客,以飨读者。由于物理内存定量分析部分用到了linux kernel虚拟内存管理的知识,读者如果有兴趣了解请看ulk3(《深入理解linux内核第三版》)内存泄露Bug现场一个线上稳定运行了三年的系统,从物理机迁移到docker环境后,运行了一段时间,突然被监控系统发出了某些实例不可用的报警。所幸有负载均衡,可以自动下掉节点,如下图所示:登录到对应机器上后,发现由于内存占用太大,触发OOM,然后被linux系统本身给kill了。应急措施紧急在出问题的实例上再次启动应用,启动后,内存占用正常,一切Okay。奇怪现象当前设置的最大堆内存是1792M,如下所示:-Xmx1792m -Xms1792m -Xmn900m -XX:PermSi ze=256m -XX:MaxPermSize=256m -server -Xss512k查看操作系统层面的监控,发现内存占用情况如下图所示:上图蓝色的线表示总的内存使用量,发现一直涨到了4G后,超出了系统限制。很明显,有堆外内存泄露了。查找线索gc日志一般出现内存泄露,笔者立马想到的就是查看当时的gc日志。本身应用所采用框架会定时打印出对应的gc日志,遂查看,发现gc日志一切正常。对应日志如下:查看了当天的所有gc日志,发现内存始终会回落到170M左右,并无明显的增加。要知道JVM进程本身占用的内存可是接近4G(加上其它进程,例如日志进程就已经到4G了),进一步确认是堆外内存导致。排查代码打开线上服务对应对应代码,查了一圈,发现没有任何地方显式利用堆外内存,其没有依赖任何额外的native方法。关于网络IO的代码也是托管给Tomcat,很明显,作为一个全世界广泛流行的Web服务器,Tomcat不大可能有堆外内存泄露。进一步查找由于在代码层面没有发现堆外内存的痕迹,那就继续找些其它的信息,希望能发现蛛丝马迹。Dump出JVM的Heap堆由于线上出问题的Server已经被kill,还好有其它几台,登上去发现它们也 占用了很大的堆外内存,只是还没有到触发OOM的临界点而已。于是就赶紧用jmap dump了两台机器中应用JVM的堆情况,这两台留做现场保留不动,然后将其它机器迅速重启,以防同时被OOM导致服务不可用。使用如下命令dump:jmap -dump:format=b,file=heap.bin [pid]使用MAT分析Heap文件挑了一个heap文件进行分析,堆的使用情况如下图所示:一共用了200多M,和之前gc文件打印出来的170M相差不大,远远没有到4G的程度。不得不说MAT是个非常好用的工具,它可以提示你可能内存泄露的点:这个cachedBnsClient类有12452个实例,占用了整个堆的61.92%。查看了另一个heap文件,发现也是同样的情况。这个地方肯定有内存泄露,但是也占用了130多M,和4G相差甚远。查看对应的代码系统中大部分对于CachedBnsClient的调用,都是通过注解Autowired的,这部分实例数很少。唯一频繁产生此类实例的代码如下所示:@Override     public void fun() {             BnsClient bnsClient = new CachedBnsClient();           // do something     return  ; }此CachedBnsClient仅仅在方法体内使用,并没有逃逸到外面,再看此类本身public class CachedBnsClient   {     private ConcurrentHashMap<String, List<String>> authCache = new ConcurrentHashMap<String, List<String>>();     private ConcurrentHashMap<String, List<URI>> validUriCache = new ConcurrentHashMap<String, List<URI>>();     private ConcurrentHashMap<String, List<URI>> uriCache = new ConcurrentHashMap<String, List<URI>>(); ...... }没有任何static变量,同时也没有往任何全局变量注册自身。换言之,在类的成员(Member)中,是不可能出现内存泄露的。当时只粗略的过了一过成员变量,回过头来细想,还是漏了不少地方的。更多信息由于代码排查下来,感觉这块不应该出现内存泄露(但是事实确是如此的打脸)。这个类也没有显式用到堆外内存,而且只占了130M,和4G比起来微不足道,还是先去追查主要矛盾再说。使用jstack dump线程信息现场信息越多,越能找出蛛丝马迹。先用jstack把线程信息dump下来看下。 这一看,立马发现了不同,除了正常的IO线程以及框架本身的一些守护线程外,竟然还多出来了12563多个线程。"Thread-5" daemon prio=10 tid=0x00007fb79426e000 nid=0x7346 waiting on condition [0x00007fb7b5678000]    java.lang.Thread.State: TIMED_WAITING (sleeping) at java.lang.Thread.sleep(Native Method) at com.xxxxx.CachedBnsClient$1.run(CachedBnsClient.java:62)而且这些正好是运行再CachedBnsClient的run方法上面!这些特定线程的数量正好是12452个,和cachedBnsClient数量一致!再次check对应代码原来刚才看CachedBnsClient代码的时候遗漏掉了一个关键的点!    public CachedBnsClient(BnsClient client) {         super();         this.backendClient = client;         new Thread() {             @Override             public void run() {                 for (; ; ) {                     refreshCache();                     try {                         Thread.sleep(60 * 1000);                     } catch (InterruptedException e) {                         logger.error("出错", e);                     }                 }             }     }这段代码是CachedBnsClient的构造函数,其在里面创建了一个无限循环的线程,每隔60s启动一次刷新一下里面的缓存!找到关键点在看到12452个等待在CachedBnsClient.run的业务的一瞬间笔者就意识到,肯定是这边的线程导致对外内存泄露了。下面就是根据线程大小计算其泄露内存量是不是确实能够引起OOM了。发现内存计算对不上由于我们这边设置的Xss是512K,即一个线程栈大小是512K,而由于线程共享其它MM单元(线程本地内存是是现在线程栈上的),所以实际线程堆外内存占用数量也是512K。进行如下计算:12563 * 512K = 6331M = 6.3G整个环境一共4G,加上JVM堆内存1.8G(1792M),已经明显的超过了4G。(6.3G + 1.8G)=8.1G > 4G如果按照此计算,应用应用早就被OOM了。怎么回事呢?为了解决这个问题,笔者又思考了好久。如下所示:Java线程底层实现JVM的线程在linux上底层是调用NPTL(Native Posix Thread Library)来创建的,一个JVM线程就对应linux的lwp(轻量级进程,也是进程,只不过共享了mm_struct,用来实现线程),一个thread.start就相当于do_fork了一把。其中,我们在JVM启动时候设置了-Xss=512K(即线程栈大小),这512K中然后有8K是必须使用的,这8K是由进程的内核栈和thread_info公用的,放在两块连续的物理页框上。如下图所示:众所周知,一个进程(包括lwp)包括内核栈和用户栈,内核栈+thread_info用了8K,那么用户态的栈可用内存就是:512K-8K=504K如下图所示:Linux实际物理内存映射事实上linux对物理内存的使用非常的抠门,一开始只是分配了虚拟内存的线性区,并没有分配实际的物理内存,只有推到最后使用的时候才分配具体的物理内存,即所谓的请求调页。如下图所示:查看smaps进程内存使用信息使用如下命令,查看cat /proc/[pid]/smaps > smaps.txt实际物理内存使用信息,如下所示:7fa69a6d1000-7fa69a74f000 rwxp 00000000 00:00 0  Size:                504 kB Rss:                  92 kB Pss:                  92 kB Shared_Clean:          0 kB Shared_Dirty:          0 kB Private_Clean:         0 kB Private_Dirty:        92 kB Referenced:           92 kB Anonymous:            92 kB AnonHugePages:         0 kB Swap:                  0 kB KernelPageSize:        4 kB MMUPageSize:           4 kB 7fa69a7d3000-7fa69a851000 rwxp 00000000 00:00 0  Size:                504 kB Rss:                 152 kB Pss:                 152 kB Shared_Clean:          0 kB Shared_Dirty:          0 kB Private_Clean:         0 kB Private_Dirty:       152 kB Referenced:          152 kB Anonymous:           152 kB AnonHugePages:         0 kB Swap:                  0 kB KernelPageSize:        4 kB MMUPageSize:           4 kB搜索下504KB,正好是12563个,对了12563个线程,其中Rss表示实际物理内存(含共享库)92KB,Pss表示实际物理内存(按比例共享库)92KB(由于没有共享库,所以Rss==Pss),以第一个7fa69a6d1000-7fa69a74f000线性区来看,其映射了92KB的空间,第二个映射了152KB的空间。如下图所示:挑出符合条件(即size是504K)的几十组看了下,基本都在92K-152K之间,再加上内核栈8K(92+152)/2+8K=130K,由于是估算,取整为128K,即反映此应用平均线程栈大小。注意,实际内存有波动的原因是由于环境不同,从而走了不同的分支,导致栈上的增长不同。重新进行内存计算JVM一开始申请了-Xmx1792m -Xms1792m即1.8G的堆内内存,这里是即时分配,一开始就用物理页框填充。12563个线程,每个线程栈平均大小128K,即:128K * 12563=1570M=1.5G的对外内存取个整数128K,就能反映出平均水平。再拿这个128K * 12563 =1570M = 1.5G,加上JVM的1.8G,就已经达到了3.3G,再加上kernel和日志传输进程等使用的内存数量,确实已经接近了4G,这样内存就对应上了!(注:用于定量内存计算的环境是一台内存用量将近4G,但还没OOM的机器)为什么在物理机上没有应用Down机笔者登录了原来物理机,应用还在跑,发现其同样有堆外内存泄露的现象,其物理内存使用已经达到了5个多G!幸好物理机内存很大,而且此应用发布还比较频繁,所以没有被OOM。Dump了物理机上应用的线程,一共有28737个线程,其中28626个线程等待在CachedBnsClient上。同样用smaps查看进程实际内存信息,其平均大小依旧为128K,因为是同一应用的原因继续进行物理内存计算1.8+(28737 * 128k)/1024K =(3.6+1.8)=5.4G进一步验证了我们的推理。这么多线程应用为什么没有卡顿因为基本所有的线程都睡眠在 Thread.sleep(60 * 1000);//一次睡眠60s上。所以仅仅占用了内存,实际占用的CPU时间很少。总结查找Bug的时候,现场信息越多越好,同时定位Bug必须要有实质性的证据。例如内存泄露就要用你推测出的模型进行定量分析。在定量和实际对不上的时候,深挖下去,你会发现不一样的风景!