系列文章目录

提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
例如:第一章 Python 机器学习入门之pandas的使用


文章目录

  • 系列文章目录
  • 前言
  • 一、Blocked状态
    • 1.案例一
    • 2.案例二
    • 3.案例三
  • 二、高低端机区分
    • 1.WebView预加载
  • 三、磁盘IO耗时
    • 1.外置存储卡路径复用
    • 2.SD卡路径复用
  • 总结

前言


一、Blocked状态

1.案例一

该案例为应用内主子线程锁抢占,由于应用内主线程下载View展示与子线程中下载缓存刷新锁抢占,部分低端机上系统资源不足,从而产生的ANR。

查看trace文件中主线程堆栈可知,主线程中实例对象被237线程所持有,继而查看237线程堆栈如下:

通过堆栈中transact调用可知,系统资源不足。分析系统相关类调用,可以发现主线程和thread-237同时调用了ContextImp中方法。
主线程中getTheme调用

线程237中ensureExternalDirsExistOrFilter调用:

ensureExternalDirsExistOrFilter调用:

咨询了框架组的同事,得到如下回复

1.调用getPhoneStorageState()和getExternalStorageState()等接口时,
此接口存在I0耗时且容易卡在PKMS\MountService binder返回
2.手机硬件老化时,IO耗时变长,调用此类接口有很大的几率会被卡住
3.插入损坏的SD卡时,调用此类接口有很大的几率会被卡住

由上可知ContextImp中ensureExternalDirsExistOrFilter和getTheme都锁住了同一个对象mSync,追踪原来是mSync这把锁锁住主线程,因此本案例的最终解决方案是,减少子线程237中系统类的交互,继而减少耗时等待。通过FileCache工具类初始化一个变量存储FileUtils.getStoragePath文件路径,减少doRefreshVideoCache时交互的频率,减小卡住的机率,详细可参考:

 private static List<String> mSdcardPaths = null;/*** SD卡路径获取* @return SdcardPath列表*/public static List<String> getSdcardPaths(){if (mSdcardPaths == null){mSdcardPaths = FileUtils.getStoragePath(XxxApplication.getApplication());}return mSdcardPaths;}

解决思路:采取空间换时间的原则。

2.案例二

该案例为应用启动阶段主线程与FacebookSDK锁抢占,比案例一相对复杂。
可借鉴思路:从问题源头逐一追踪阻塞主线程锁的持有链。

由堆栈可知,主线程与线程39之间产生了资源等待,继而查看thread-39堆栈:

由关键字held by可知,线程39与主线程资源等待的原因为,同时都在使用Shareprefrence,线程39通过getPreferencesDir方法获取sp路径时候产生了等待。同时可以看到,线程39与线程38产生了线程等待,继而查看thread-38堆栈:

这里可能会有个疑问,线程38中获取文件路径为什么会跟线程39中Sharepreference获取产生资源竞争呢?如果你熟悉sp就会马上反应过来,sp的本质也是一个xml文件。不熟悉也没关系,我们接着观察分析,会发现thread-38和thread-39最终都调用了ContextImp中方法,继而查看:
thread-38中ContextImpl.getExternalFilesDirs调用

内部ensureExternalDirsExistOrFilter调用:

ensureExternalDirsExistOrFilter方法分析可参考案例一。

thread-39中ContextImpl.getPreferencesDir调用

由上可知,thread-38中ContextImpl.getExternalFilesDirs方法,以及thread-39中ContextImpl.getPreferencesDir方法,都锁住了同一个对象mSync。接下来再去分析具体业务堆栈,thread-38中详细调用:

由于保密原则,只能贴出大概的调用,后续的追踪为:通过此处可以定位到thread-38中,我们应用通过RxJava开启了一个子线程进行相关的初始化,而这个调用的时机是自定义的一个ContentProvider的onCreate阶段。而主线程中FacebookSDK的初始化,SDK内部也是通过一个Provider进行初始化,二者在同一时间段进行,故而造成了thread-38中Rx子线程抢占了资源,从而导致主线程中FacebookSDK的初始化阻塞。最终解决方式是,将二者的初始化时机进行排序,错开调度。当然,也可以将thread-38中的初始化时机放到应用Application的onCreate阶段,经测试也是ok的。原则就是将二者调度时机避开,避免资源抢夺。
总结,该问题相对复杂,解决的思路一是依赖trace.txt文件的分析经验,找出阻塞点,其次是业务代码的追踪和SDK内部逻辑的熟悉。

3.案例三

可借鉴思路:涉及三方库沟通,单一日志无法明确问题时,可同一问题的多个场景整理综合分析,得出最终结论。

由主线程中关键字held by后面信息可知,主线程被thread-27所阻塞,继而查看thread-27堆栈如下:

比较二者的调用可知,thread-27和主线程同时调用了ContextImp中方法,继而查看:
thread-27中ContextImpl.getExternalFilesDirs调用:

内部ensureExternalDirsExistOrFilter调用:

ensureExternalDirsExistOrFilter方法分析可参考案例一。

main-thread中ContextImpl.getTheme调用:

分析:thread-27中ContextImpl.getExternalFilesDirs与main-thread中ContextImpl.getTheme方法,竞争的是同一把锁mSync,主线程获取不到锁从而阻塞。由于thread-27中为应用接入的xx广告SDK,故而将同一类场景进行归纳进行了分析,
场景二:


场景二同样为xx广告与业务动画调用时ContextImpl.getTheme资源争夺,导致的主线程阻塞。
场景三:


场景三为底部播放栏设置Drable时,调用ContextImpl.getTheme资源争夺,导致的主线程阻塞。

由上述场景综合分析,基本可以确定此处是,xx广告SDK内部的问题,SDK内部代码追踪发现StorageUtils.getOfflineCacheDirectory调用较为频繁,最终与SDK厂商进行沟通反馈解决该问题。

二、高低端机区分

1.WebView预加载

main (native):tid=1 systid=1184
#00 pc 0x65cb78 TrichromeLibrary.apk + 50409472at J.N.M1Y_XVCN(N.java)at org.chromium.content.browser.BrowserStartupControllerImpl.a(BrowserStartupControllerImpl.java:2)at org.chromium.content.browser.BrowserStartupControllerImpl.g(BrowserStartupControllerImpl.java:8)at y8.run(y8.java:23)at org.chromium.base.ThreadUtils.f(ThreadUtils.java:2)at mA0.h(mA0.java:41)at mA0.b(mA0.java:20)at mA0.j(mA0.java:2)at com.android.webview.chromium.WebViewChromiumFactoryProvider.g(WebViewChromiumFactoryProvider.java:2)at com.android.webview.chromium.WebViewChromium.init(WebViewChromium.java:14)at android.webkit.WebView.<init>(WebView.java:435)at android.webkit.WebView.<init>(WebView.java:355)at android.webkit.WebView.<init>(WebView.java:337)at android.webkit.WebView.<init>(WebView.java:324)at android.webkit.WebView.<init>(WebView.java:314)at com.xxx.ui.mall.view.BPWebView.<init>(BPWebView.java:100)at com.xxx.ui.main.MainActivity$4.queueIdle(MainActivity.java:595)at android.os.MessageQueue.next(MessageQueue.java:404)at android.os.Looper.loop(Looper.java:183)at android.app.ActivityThread.main(ActivityThread.java:7740)at java.lang.reflect.Method.invoke(Method.java)at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:612)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:997)

日志分析定位到MainActivity$4.queueIdle,而该方法只是进行了自定义BPWebView的预加载,BPWebView只是简单继承了WebView,并无过多额外操作,最终通过区分高低端机,低端机不进行WebView预加载,解决该问题。

MainActivity$4.queueIdle

        Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {@Overridepublic boolean queueIdle() {Looper.myQueue().removeIdleHandler(this);long[] m = PhoneLevelUtil.getDeviceMemory();if (m[1] * 100 / m[0] > 15) {//BPWebView wb = new BPWebView(MusicApplication.getInstance());String gameCenterUrl = DynamicIconUtil.getUrl();if (!TextUtils.isEmpty(gameCenterUrl)) {BPWebView wbGame = new BPWebView(MusicApplication.getInstance());wbGame.setOnPageFinished(() -> {wbGame.freeMemory();});wbGame.loadUrl(gameCenterUrl);}String subHomeLink;if (TextUtils.isEmpty(SubscribePageUtil.subHomeLinkByService)) {subHomeLink = ApiUrl.H5_BASE_URL + SubscribePageUtil.SUBSCRIBE_PAGE_URL;} else {subHomeLink = ApiUrl.H5_BASE_URL + SubscribePageUtil.subHomeLinkByService;}BPWebView wbSub = new BPWebView(MusicApplication.getInstance());wbSub.setOnPageFinished(() -> {wbSub.freeMemory();});wbSub.loadUrl(subHomeLink);}return false;}});

修改:

if (!GlobalVariate.isHighDevice) {return;}//低端机预加载,系统WebView产生的ANR较多

三、磁盘IO耗时

1.外置存储卡路径复用

main (blocked):tid=1 systid=17151 | waiting to lock <0x05dfb3bd> (java.lang.Object) held by thread 46at android.app.ContextImpl.getExternalCacheDirs(ContextImpl.java:836)at android.content.ContextWrapper.getExternalCacheDirs(ContextWrapper.java:311)at androidx.core.content.ContextCompat$Api19Impl.getExternalCacheDirs(ContextCompat.java:840)at androidx.core.content.ContextCompat.getExternalCacheDirs(ContextCompat.java:459)at androidx.core.content.FileProvider.parsePathStrategy(FileProvider.java:696)at androidx.core.content.FileProvider.getPathStrategy(FileProvider.java:635)at androidx.core.content.FileProvider.attachInfo(FileProvider.java:416)at android.app.ActivityThread.installProvider(ActivityThread.java:7673)at android.app.ActivityThread.installContentProviders(ActivityThread.java:7209)at android.app.ActivityThread.handleBindApplication(ActivityThread.java:7121)at android.app.ActivityThread.access$1600(ActivityThread.java:268)at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2056)at android.os.Handler.dispatchMessage(Handler.java:106)at android.os.Looper.loop(Looper.java:268)at android.app.ActivityThread.main(ActivityThread.java:8107)at java.lang.reflect.Method.invoke(Method.java)at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:627)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:997)RxCachedThreadScheduler-4 (native):tid=46 systid=17212 at libcore.io.Linux.access(Linux.java)at libcore.io.ForwardingOs.access(ForwardingOs.java:72)at libcore.io.BlockGuardOs.access(BlockGuardOs.java:73)at libcore.io.ForwardingOs.access(ForwardingOs.java:72)at android.app.ActivityThread$AndroidOs.access(ActivityThread.java:7982)at java.io.UnixFileSystem.checkAccess(UnixFileSystem.java:281)at java.io.File.exists(File.java:815)at android.app.ContextImpl.ensureExternalDirsExistOrFilter(ContextImpl.java:3022)at android.app.ContextImpl.getExternalFilesDirs(ContextImpl.java:779)at android.app.ContextImpl.getExternalFilesDir(ContextImpl.java:768)at android.content.ContextWrapper.getExternalFilesDir(ContextWrapper.java:276)at com.xxx.storage.cache.ScopeStorageUtils.getBPRootDir(ScopeStorageUtils.java:121)at com.xxx.storage.cache.ScopeStorageUtils.getBPRootPath(ScopeStorageUtils.java:134)at com.xxx.storage.cache.ScopeStorageUtils.shouldUseScopeStorage(ScopeStorageUtils.java:49)at com.xxx.util.PhoneDeviceUtil.getMusicLocalDir(PhoneDeviceUtil.java:881)at com.xxx.util.PhoneDeviceUtil.getCacheDirPath(PhoneDeviceUtil.java:914)at com.xxx.biz.xxx.db.FilexxxerDBHelper.<init>(FilexxxerDBHelper.java:43)at com.xxx.biz.xxx.db.FilexxxerDB.initDBAndCheckUpdate(FilexxxerDB.java:49)at com.xxx.biz.xxx.db.FilexxxerDB.<init>(FilexxxerDB.java:44)at com.xxx.biz.xxx.db.FilexxxerDB.<init>(FilexxxerDB.java:38)at com.xxx.biz.xxx.db.FilexxxerDB$Holder.<clinit>(FilexxxerDB.java:60)at com.xxx.biz.xxx.db.FilexxxerDB.getInstance(FilexxxerDB.java:65)at com.xxx.storage.cache.PlaylistDB.getDB(PlaylistDB.java:57)at com.xxx.storage.cache.PlaylistDB.query(PlaylistDB.java:349)at com.xxx.storage.cache.HistoryPlaylistCache.queryDB(HistoryPlaylistCache.java:192)at com.xxx.storage.cache.HistoryPlaylistCache.<init>(HistoryPlaylistCache.java:39)at com.xxx.storage.cache.ItemCache.init(ItemCache.java:151)at com.xxx.common.base.XxApplicationInitor.init1(XxApplicationInitor.java:285)at com.xxx.common.base.XxApplicationInitor.access$500(XxApplicationInitor.java:115)at com.xxx.common.base.XxApplicationInitor$4.subscribe(XxApplicationInitor.java:177)at io.reactivex.internal.operators.observable.ObservableCreate.subscribeActual(ObservableCreate.java:40)at io.reactivex.Observable.subscribe(Observable.java:12284)at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeTask.run(ObservableSubscribeOn.java:96)at io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:578)at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)at java.util.concurrent.FutureTask.run(FutureTask.java:266)at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)at java.lang.Thread.run(Thread.java:923)

ScopeStorageUtils.getBPRootDir

    public static File getBPRootDir() {File externalFilesDir = MusicApplication.getInstance().getExternalFilesDir(null);if (externalFilesDir == null) {// Android4.4以下,externalFilesDir返回null,直接自己创建目录externalFilesDir = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+ File.separator + "Android"+ File.separator + "data"+ File.separator + MusicApplication.getInstance().getPackageName()+ File.separator + "files");}return externalFilesDir;}

由于手机硬件老化,主要耗时点为getExternalFilesDir,故解决方法为缓存getExternalFilesDir路径。

FileCache类缓存路径

private static File mExternalFilesDir = null;/*** 外置的存储卡获取* @return 外置存储卡File*/
public static File getExternalFilesDir(){if (mExternalFilesDir == null){mExternalFilesDir = XxApplication.getInstance().getExternalFilesDir("");}return mExternalFilesDir;
}

修改后ScopeStorageUtils.getBPRootDir调用:

    public static File getBPRootDir() {File externalFilesDir = FileCache.getExternalFilesDir();...return externalFilesDir;}

2.SD卡路径复用

main (blocked):tid=1 systid=545 | waiting to lock <0x08ff64d2> (java.lang.Object) held by thread 237at android.app.ContextImpl.getTheme(ContextImpl.java:387)at android.content.ContextWrapper.getTheme(ContextWrapper.java:139)at android.content.Context.getColor(Context.java:704)at androidx.core.content.ContextCompat$Api23Impl.getColor(ContextCompat.java:889)at androidx.core.content.ContextCompat.getColor(ContextCompat.java:536)at com.xxx.ui.dialog.xxx.DownLoadHintView.setViewColor(DownLoadHintView.java:228)at com.xxx.ui.dialog.xxx.DownLoadHintView.loadData(DownLoadHintView.java:361)at com.xxx.ui.dialog.xxx.DownLoadHintView.access$100(DownLoadHintView.java:79)at com.xxx.ui.dialog.xxx.DownLoadHintView$ShowRunnable.run(DownLoadHintView.java:522)at android.os.Handler.handleCallback(Handler.java:938)at android.os.Handler.dispatchMessage(Handler.java:99)at android.os.Looper.loop(Looper.java:223)at android.app.ActivityThread.main(ActivityThread.java:7815)at java.lang.reflect.Method.invoke(Method.java)at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:593)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1094)RxCachedThreadScheduler-49 (native):tid=237 systid=13518
#00 pc 0x9ae90 libc.so (__ioctl + 8)
#01 pc 0x6932f libc.so (ioctl + 26)
#02 pc 0x39a13 libbinder.so (android::IPCThreadState::talkWithDriver(bool) + 238)
#03 pc 0x3a655 libbinder.so (android::IPCThreadState::waitForResponse(android::Parcel*, int*) + 32)
#04 pc 0x3a42b libbinder.so (android::IPCThreadState::transact(int, unsigned int, android::Parcel const&, android::Parcel*, unsigned int) + 122)
#05 pc 0x35267 libbinder.so (android::BpBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int) + 98)
#06 pc 0xc73ff libandroid_runtime.so (android_os_BinderProxy_transact(_JNIEnv*, _jobject*, int, _jobject*, _jobject*, int) + 82)at android.os.BinderProxy.transactNative(BinderProxy.java)at android.os.BinderProxy.transact(BinderProxy.java:540)at android.os.storage.IStorageManager$Stub$Proxy.mkdirs(IStorageManager.java:2695)at android.os.storage.StorageManager.mkdirs(StorageManager.java:1405)at android.app.ContextImpl.ensureExternalDirsExistOrFilter(ContextImpl.java:2895)at android.app.ContextImpl.getExternalFilesDirs(ContextImpl.java:771)at android.content.ContextWrapper.getExternalFilesDirs(ContextWrapper.java:278)at com.xxx.util.FileUtils.getScopeStoragePath(FileUtils.java:107)at com.xxx.util.FileUtils.getStoragePath(FileUtils.java:96)at com.xxx.biz.download.utils.LocalMediaCache.doRefreshVideoCache(LocalMediaCache.java:1065)at com.xxx.biz.download.utils.LocalMediaCache.doScanLocalVideo(LocalMediaCache.java:1155)at com.xxx.biz.download.utils.LocalMediaScaner$1.onNext(LocalMediaScaner.java:40)at com.xxx.biz.download.utils.LocalMediaScaner$1.onNext(LocalMediaScaner.java:28)at io.reactivex.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.drainNormal(ObservableObserveOn.java:201)at io.reactivex.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.run(ObservableObserveOn.java:255)at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)at java.util.concurrent.FutureTask.run(FutureTask.java:266)at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)at java.lang.Thread.run(Thread.java:923)

FileUtils.getScopeStoragePath

List<String> getScopeStoragePath(Context mContext, boolean... isRemoveAble) {List<String> allSdcardPath = new ArrayList<>();try {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {File[] externalFilesDirs = mContext.getExternalFilesDirs("");...} else {File externalFilesDir = mContext.getExternalFilesDir("");...}} catch (Exception e) {Log.e("FileUtils", "getScopeStoragePath: ", e);}return allSdcardPath;
}

由于手机硬件老化,主要耗时点为getExternalFilesDirs,故解决方法为缓存getExternalFilesDirs路径。

FileCache类缓存路径

private static List<String> mSdcardPaths = null;/*** SD卡路径获取* @return SdcardPath列表*/
public static List<String> getSdcardPaths(){if (mSdcardPaths == null){mSdcardPaths = XxApplication.getApplication().getExternalFilesDirs("");}return mSdcardPaths;
}

修改后FileUtils.getScopeStoragePath

List<String> getScopeStoragePath(Context mContext, boolean... isRemoveAble) {List<String> allSdcardPath = new ArrayList<>();try {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {File[] externalFilesDirs = FileCache.getSdcardPaths();...} else {File externalFilesDir = FileCache.getExternalFilesDir();...}} catch (Exception e) {Log.e("FileUtils", "getScopeStoragePath: ", e);}return allSdcardPath;
}

总结

ANR实战案例3 - 应用在部分低端机ANR优化案例相关推荐

  1. 不改一行业务代码,飞书 iOS 低端机启动优化实践

    动手点关注 干货不迷路 

  2. 《Unity 4 3D开发实战详解》一6.7 物理引擎综合案例

    本节书摘来异步社区<Unity 4 3D开发实战详解>一书中的第6章,第6.7节,作者: 吴亚峰 , 杜化美 , 张月霞 , 索依娜 责编: 张涛,更多章节内容可以访问云栖社区" ...

  3. Day814.电商系统表设计优化案例分析 -Java 性能调优实战

    电商系统表设计优化案例分析 Hi,我是阿昌,今天学习记录的是关于电商系统表设计优化案例分析. 如果在业务架构设计初期,表结构没有设计好,那么后期随着业务以及数据量的增多,系统就很容易出现瓶颈. 如果表 ...

  4. 【中亦安图】清算/报表/日终跑批程序之性能优化案例(5)

    第一章 技术人生系列 · 我和数据中心的故事(第五期)-清算/报表/日终跑批程序之性能优化案例(一) 中亦安图 | 2016-02-18 21:40 前言 不知不觉,技术人生系列·我和数据中心的故事来 ...

  5. 突破性能瓶颈!ElasticSearch百亿级数据检索优化案例

    一.前言 本文中的数据平台已迭代三个版本,从头开始遇到很多常见的难题,终于有片段时间整理一些已完善的文档,在此分享以供所需朋友的.实现参考,少走些弯路,在此篇幅中偏重于ES的优化,目前生产已存储百亿数 ...

  6. 1.4_26 Axure RP 9 for mac 高保真原型图 - 案例25【中继器 - 后台管理系统3】优化- 3D按钮、键盘操作

    相关链接 目录 Axure中文学习网 AxureShop AxureShop-QA 案例目标  1. 了解3D按钮效果的实现方式 一.成品效果 Axure Cloud 案例25[中继器 - 后台管理系 ...

  7. sql的不等于条件优化_SQL优化案例(2):OR条件优化

    随后上一篇文章< SQL优化案例(1):隐式转换>的介绍,此处内容围绕OR的优化展开. 在MySQL中,同样的查询条件,如果变换OR在SQL语句中的位置,那么查询的结果也会有差异,在多个复 ...

  8. 数据库优化案例——————某市中心医院HIS系统

    记得在自己学习数据库知识的时候特别喜欢看案例,因为优化的手段是容易掌握的,但是整体的优化思想是很难学会的.这也是为什么自己特别喜欢看案例,今天也开始分享自己做的优化案例. 最近一直很忙,博客产出也少的 ...

  9. 老李案例分享:Weblogic性能优化案例

    老李案例分享:Weblogic性能优化案例 POPTEST的测试技术交流qq群:450192312 网站应用首页大小在130K左右,在之前的测试过程中,其百用户并发的平均响应能力在6.5秒,性能优化后 ...

最新文章

  1. 如何判断是否丢掉用户请求(转载)
  2. malloc函数分配失败处理的严重性
  3. php mysql可以跨站_PHP防跨站之open_basedir目录设置
  4. try catch 有多烦人,我就有多暴躁!一次搞定 Exception ^ ^
  5. 韩国IT业是怎么走向国际我们须要学习什么
  6. C++学习笔记:类的成员函数的声明与定义
  7. Silverlight4中用net.tcp双工方式进行通信
  8. leetcode 795. Number of Subarrays with Bounded Maximum | 795. 区间子数组个数(Java)
  9. python configparser模块来 读取 、 创建 和 修改 配置文件
  10. 查看端口命令及端口功能详解
  11. html中鼠标移走的伪元素,a标签的伪元素的应用——link,hover,visited,active
  12. java下载文件下载不动_JAVA实现文件下载,浏览器端得到数据没反应
  13. 华为防火墙配置命令大全,超级详细
  14. 【Pytorch】测试单张图片(调用transforms)
  15. mac 快速显示/隐藏隐藏文件快捷键
  16. [教程]人脸识别_打卡签到_系统qt界面
  17. 编译原理中的first集,follow集和selec集的小解
  18. Android ImageView 四个角自定义角度,以及角度的变换
  19. 西门子PLC S7-200和S7-300有什么差别?如何进行远程上下载?
  20. OutputStream的flush()方法

热门文章

  1. java中int范围补码详解
  2. 什么是Java常量?常量定义
  3. 比例—微分控制调节二阶系统
  4. 有关LOGO设计软件
  5. 【慕课网实战课程笔记】Vue.js高仿饿了么外卖App
  6. 程序计数器、指令寄存器的区别
  7. 搭建nagios监控平台
  8. 求解离散黎卡提矩阵代数方程
  9. ubuntu react-native run-android 报watchman的错误
  10. java安装教程win10_Java安装教程win10