4b60e6806333286b8f3c1faa1d7b7ef1.png

作者: 邹阿涛涛涛涛涛涛

出自:掘金

原文: https://juejin.im/post/5d617d6851882575e8054fab


前言

这是我在掘金的第一篇博客分享,最近在掘金上看了许多大佬的文章,学到了非常多的东西,实在是忍不住想要把我们平时工作中用到的一些优化方案分享出来。其实也是一个大家一起讨论学习的过程,希望大家可以多多交流 ~

背景

先简单讲讲跟oom纠结的历史吧。在18年年底,我们app进行了一次非常大的版本更迭,因为时间紧急、业务繁忙、人数也没达到可以凑人数可以让某些人准点下班的那种数量(各个公司的常规原因)。业务线在对一些模块进行重构和大量新需求的开发过程中,许许多多的细节没有注意到,直接导致了后面一个月的崩溃率、OOM率猛增, 且居高不下。大概快到了千分之2的这个数量级,这是非常非常恐怖的。因此我们花了一段时间,集中的fix了一把OOM的相关问题,一顿操作,直接让主版本的崩溃率来到了「万分之一」,OOM率来到了十万分之一这个数量级。

干掉OOM,我们干了什么?

不讲废话了,也不讲那些网上都可以查到的一些常规优化方法来填字数了,我会针对如何去fix OOM这个目标,将思考的历程以及解决问题的办法分享出来,希望其中会有某一条经验正好击中你们,能起到一些帮助~~开干!!下面的内容,我会用一级标题的字体~ 显眼一些哈哈,毕竟前面都是啰嗦的废话

11d68ba57f110c2f31f566872f504add.png

一、排查内存泄漏

首先fix OOM第一件事肯定是来排查内存泄漏。想要排查内存泄漏,那就第一步要对内存泄漏进行监控、上报。

我们采用了LeakCanary,实现了一个自定义的Service继承自DisplayLeakService,重写afterDefaultHandling方法,将内存泄漏上报到Sentry。

样例代码如下:

public static class LeakReportService extends DisplayLeakService {
@SuppressWarnings("ThrowableNotThrown")
@Override
protected void afterDefaultHandling(@NonNull HeapDump heapDump, @NonNull AnalysisResult result, @NonNull String leakInfo) {if (!result.leakFound || result.excludedLeak) {return;}try {Exception exception = new Exception("Memory Leak from LeakCanary");exception.setStackTrace(result.leakTraceAsFakeException().getStackTrace());Sentry.capture(exception);} catch (Exception e) {e.printStackTrace();}}
}

当内存泄漏上报到sentry上面之后,我们直接观察是哪里泄漏的就好了。通过sentry进行监控之后,项目里面的大部分内存泄漏无处可逃~ ,内存泄漏比较简单,我就不花大量篇幅去赘述了~,我自己看文章的过程中,最讨厌篇幅太长。。。

除了LeakCanary,我们还使用了Android Studio自带的Profiler工具对内存有进行分析,包括内存泄漏的问题和内存峰值过高的问题。

profiler工具的使用方法我就不赘述了吧,讲一下小技巧吧。在排查bitmap对象,我们可以用Profiler直接看java 堆中的bitmap对象图片的预览~ 这样可以直接定位到是哪里泄漏了以及哪里bitmap加载过大

方法:找到对应的Bitmap对象,然后~ ,点击它,然后就可以preview,如下图:

beb905ab0866fcc57c0666fd933642e4.png

二、兜底策略

我们可以知道的是,当一个Activity的生命周期要走完了,那就说明我们绝大概率不会再使用这个Activity对象了。因此完全可以对他的可能导致整个Activity泄露的引用进行清空,将其中的一些资源释放干净,比如有EditText的TextWatcher,这是非常容易泄露且在我们项目中大量出现的一个case。然后,于是乎我们加上了更加丧心病狂的兜底策略,话不多说,直接上代码:

private void traverse(ViewGroup root) {final int childCount = root.getChildCount();for (int i = 0; i < childCount; ++i) {final View child = root.getChildAt(i);if (child instanceof ViewGroup) {child.setBackground(null);traverse((ViewGroup) child);} else {if (child != null) {child.setBackground(null);}if (child instanceof ImageView) {((ImageView) child).setImageDrawable(null);} else if (child instanceof EditText) {((EditText) child).cleanWatchers();}}}
}

我们在基类BaseActivity的onDestory()方法中进行了一些资源和引用的清除。

三、内存峰值太高

在我们把能fix的内存泄漏都盘了一遍之后,上线一周并没有发现数据好转,OOM率还是高居不下。于是乎,我们开始怀疑内存峰值太高的问题。在我们的项目中不仅仅只有native的部分模块,还有混合的H5、RN模块,当起一个ReactActivity的实例时,内存峰值总是涨的特别特别厉害,同时项目中有消息流的展现,其中会包含着大量的图片展示,这也是导致内存峰值太高的原因(Bitmap对象太大以及太多)我们又拿出了老伙伴 - Profiler,这可是分析bitmap对象的利器,可以直接看到大小、图片的预览,以及可以通过 go to instance一层一层的找到到底是谁在引用它。比如下面这个例子,直接看引用就知道是被Fresco所引用了~ 直接就在CountingMemoryCache中。

c0c1310a9df558ed37b54061d539513a.png

其实我们主要还是需要去关注Bitmap对象的分配和不合法持有导致的内存峰值问题,如果一个bitmap对象有3M,然后持有一个几十上百个在内存中,这谁吃得消,低端机器老早直接OOM了。

查Bitmap分配查出来的问题

目前我们项目中用的图片加载框架有两个,UIL、Fresco,UIL我吐槽很久了,这么多年没更新,老早就该换了~ 1. UIL加载图片在我们项目中的问题:

  • 没有传入合适的Config,绝大多数地方传的都是ARGB_8888,其实根本没必要,改成565直接少一半内存占用
  • 用UIL进行loadImage时,没有传入targetSize,这就直接导致了UIL内部是以屏幕的尺寸去Decode的Bitmap对象,想象一下,一个特别小的头像View,持有着一个屏幕大小尺寸的Bitmap对象,这谁顶得住。
  • 许多地方不需要存内存缓存,比如闪屏广告图,app启动之后就不会再使用了,可以加载的时候 memoryCache(false)
  • 许多地方不需要磁盘缓存,比如发布动态,从图库中选图,不需要再存一份磁盘缓存了,本身那些图片都是本地图片。直接 diskCache(false)

2.Fresco在RN页面中使用的问题,通过看代码可以知道,RN页面销毁的时候,连带着Fresco的内存缓存都会被清空,直接上代码图:

3735a202c7c7235f60bcf3d3a7772af5.png

代码看到这里,似乎Fresco不用担心了,既然会清空Fresco的内存缓存,何愁会引起内存峰值过高,如果读者看到这里,也有这个想法,那就大错特错了。话不多说,直接上图。

6ade1f68d3f19c18df0ab7f20c48f993.png

Fresco相关源码的逻辑这篇文章就不分析了,主要讲思路,具体的源码分析后面我会用单独的篇幅去讲~ 为什么我会对Fresco的动图缓存这么敏感?那还是Profiler的功劳,我在用Profiler查看内存中bitmap的分配的时候,发现有上百张的Loading图没有销毁(我们Loading图是动图,大概每帧的Bitmap对象在360K左右), 且打开的页面越多,Loading的bitmap就会越多。(这是因为我们每一个RN页面都会带一个Loading动画)0.3M * 100 = 30M,不少了。。。,说实话有点恐怖于是乎,干掉他们,这里用了反射,正常情况下不需要反射。直接拿ImagePipelineFactory中的对象来clear就好

public static void clearAnimationCache() {
if (frescoAnimationCache == null) {
//采用反射的方法,如果native、rn同时初始化Fresco,会造成Fresco内部存储动图的//CountingMemoryCache不是Fresco.getImagePipelineFactory().getBitmapCountingMemoryCache()了
//暂时用反射的方法,拿到存储动图缓存的cache,并清空
try {Class imagePipelineFactoryClz = Class.forName("com.facebook.imagepipeline.core.ImagePipelineFactory");
Field mAnimatedFactoryField = imagePipelineFactoryClz.getDeclaredField("mAnimatedFactory");mAnimatedFactoryField.setAccessible(true);AnimatedFactoryV2Impl animatedFactoryV2 = (AnimatedFactoryV2Impl) mAnimatedFactoryField.get(Fresco.getImagePipelineFactory());Class animatedFactoryV2ImplClz = Class.forName("com.facebook.fresco.animation.factory.AnimatedFactoryV2Impl");Field mBackingCacheField = animatedFactoryV2ImplClz.getDeclaredField("mBackingCache");mBackingCacheField.setAccessible(true);frescoAnimationCache = (CountingMemoryCache) mBackingCacheField.get(animatedFactoryV2);} catch (Exception e) {Log.e("FrescoUtil", e.getMessage(), e);}
}
if (frescoAnimationCache != null) {frescoAnimationCache.clear();
}
Fresco.getImagePipelineFactory().getBitmapCountingMemoryCache().clear();
Fresco.getImagePipelineFactory().getEncodedCountingMemoryCache().clear();
}

又一个兜底方案

为了防止峰值过高,我们还起了一个线程,定时的去监控实时的内存使用情况,如果内存紧急了,直接清空UIL/Fresco的内存缓存救急

private static Handler lowMemoryMonitorHandler;private static final int MEMORY_MONITOR_INTERVAL = 1000 * 60;/*** 开启低内存监测,如果低内存了,作出相应的反应*/public static void startMonitorLowMemory() {HandlerThread thread = new HandlerThread("thread_monitor_low_memory");thread.start();lowMemoryMonitorHandler = new Handler(thread.getLooper());lowMemoryMonitorHandler.postDelayed(releaseMemoryCacheRunner, MEMORY_MONITOR_INTERVAL);}/*** 低内存时清空Fresco、UIL的内存缓存* 如果已用内存达到了总的 80%时,就清空缓存*/
private static Runnable releaseMemoryCacheRunner = new Runnable() {
@Override
public void run() {long alreadyUsedSize = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();long maxSize = Runtime.getRuntime().maxMemory();if (Double.compare(alreadyUsedSize, maxSize * 0.8) == 1) {BitmapUtil.clearMemoryCaches();}lowMemoryMonitorHandler.postDelayed(releaseMemoryCacheRunner, MEMORY_MONITOR_INTERVAL);}
};

五、特大图排查优化

我想大家都不会想到,在我们app的登录注册页,会有一个图片轮播控件,它轮播着五六张单张6M+的Bitmap。。。当然,特大图不仅限于此,还有其他地方会有相同情况,我们通过Profiler找出那些大的bitmap对象,然后预览之后确定是哪里在用的。直接优化掉。最不济 8888 -> 565就少一半内存占用怎么讲呢,,OOM这个东西,还没咋僵持呢,就没了。

六、总结

深夜一时兴起想分享和记录一些什么,就随便写了这一篇博客,写的不详细,没有排版和良好的语言组织,单纯的就是想分享总结一下吧,我们为了fix OOM所做的事情:

  1. 检查内存泄漏,包括常见的Context泄漏、单例泄漏、EditText的TextWatcher泄漏等等,找到并fix他们,最简单的例子,能传application的地方就不要硬传个activity过去
  2. 兜底方案:
  • 在Activity onDestory的时候,遍历View树,清空backGround、Drawable、EditText的TextWatcher等
内存峰值的优化。内存泄漏会导致内存峰值,内存峰值是OOM的大锅,举个例子当可用内存不够分配一个Bitmap对象时,就会OOM,Android上大多数的内存峰值都是图片的加载带来的。现在许多的app中都有信息流的展现,可能会有许多的九宫格展示图片,且Bitmap对象本身就可以非常大。
  • 优化UIL的使用
    • memoryCache选用,不是所有的图片加载都需要UIL去塞一份内存缓存的,比如闪屏图
    • ImageLoader.getInstance().displayImage()的时候,传进去的Option不要无脑ARGB_8888,讲道理来说,无脑RGB_565都是没啥问题的。。
    • 调用displayImage的时候,最好传一个ImageSize作为targetSize,这个size可以是你的ImageView的尺寸,当View尺寸本身不确定的时候,可以传一个大概值,比如我们app中有好些个的头像标准尺寸,为了偷懒,直接传MaxAvatarSize就ok
  • Fresco的优化
    • RN中使用Fresco加载图片,在RN Activity销毁的时候,会将Fresco默认的memory cache清空,但是动图的缓存没有清。手动清一下。我们项目中每个RN页面都会带一个Loading动图,所以吃了大亏。。
持续的后台监控内存,起一个HandlerThread,一直在后台拿内存使用的状态,达到了危险警戒线就清空一把UIL、Fresco的memory cache,先让世界安静一下需要对内存泄漏、OOM、Crash、ANR进行监控

一些其他的细节暂时想不起来了,凌晨四点脑子不清醒了。


推荐阅读:

java钢铁侠-马克51号:Bigo的Java面试,我挂在了第三轮技术面上.........​zhuanlan.zhihu.com
fc3c460e5b3f45b36715521529b4a8c6.png
java钢铁侠-马克51号:rrayList集合为什么不能使用foreach增加、删除、修改元素​zhuanlan.zhihu.com
3171ce6b56e3e798d09348a6ccb9d7fa.png
java钢铁侠-马克51号:如何设计 QQ、微信、微博、Github 等等,第三方账号登陆 ?(附表设计)​zhuanlan.zhihu.com
f94f349e8547130bce5d8ff17371184b.png
activity重启图片没有加载_加载那么多小姐姐的脉脉,怎么没OOM?

相关文章

  1. 使用 Flash Builder 的 Apple iOS 开发过程

    使用 Flash Builder 的 Apple iOS 开发过程 iOS 开发和部署过程概述 构建、调试或部署 iOS 应用程序前的准备工作 在测试、调试或安装 iOS 应用程序时选择的文件 将应用程序部署到 Apple App Store 时选择的文件 在使用 Flash Builder 开发 iOS 应用程序之前&#xff0c;必须…...

    2023/3/16 19:40:03
  2. exchange日常管理之九:升级SP1后的灾难恢复

    将exchange 2007升级到了exchange 2010&#xff0c;但是没有打最新的SP1补丁和累积更新&#xff0c;没想到这补丁一打就出问题了&#xff0c;汗了一把啊。 升级过程摘要 1、在前端服务器和后端服务器上安装microsoft office filter pack 2.0 2、停掉后端的beremote备份进程 3…...

    2023/3/16 17:29:51
  3. iOS开发 - js oc相互调用

    2019独角兽企业重金招聘Python工程师标准>>> 首先导入 JavaScriptCore.framework 框架 #import <UIKit/UIKit.h> #import <Foundation/Foundation.h> #import <JavaScriptCore/JavaScriptCore.h>protocol ServerJSProtocol <JSExport>// 微…...

    2023/3/16 6:11:48
  4. git学习之创建版本库

    创建版本库 什么是版本库呢&#xff1f;版本库又名仓库&#xff0c;英文名repository&#xff0c;你可以简单理解成一个目录&#xff0c;这个目录里面的所有文件都可以被Git管理起来&#xff0c;每个文件的修改、删除&#xff0c;Git都能跟踪&#xff0c;以便任何时刻都可以追踪…...

    2023/3/16 5:38:29
  5. List集合中的数据按照某一个属性进行分组

    有的时候&#xff0c;我们需要在java中对集合中的数据进行分组运算。例如&#xff1a;Bill对象有money(float)和type(String)属性&#xff0c;现有个集合List<Bill>&#xff0c;需要按照Bill的type属性进行分组&#xff0c;计算money的总和。有以下两种思路&#xff1a; …...

    2023/3/18 2:30:34
  6. 游戏编程性能优化--------------------------------------------------------------------------------------...

    游戏编程性能优化------------------------------------------------------------------------------------------- 1.全局变量名尽量用缩写&#xff0c;尽可能短&#xff0c;可以减小程序最终生所的体积 2.for循环在较大的循环空间&#xff0c;写成几个循环&#xff0c;以利用…...

    2023/3/16 12:35:44
  7. 2017年软件工程作业-“Hello World!”团队互评beta版本

    A.欢迎来怼——博客园安卓APP&#xff08;测评人&#xff1a;刘淑霞&#xff09; 博客地址&#xff1a;http://www.cnblogs.com/liusx0303/p/7905928.html B.Thunder——爱阅app&#xff08;测评人&#xff1a;方铭&#xff09; 博客地址&#xff1a;http://www.cnblogs.com/…...

    2023/3/16 12:07:11
  8. ibatis 批量插入逻辑

    为什么80%的码农都做不了架构师&#xff1f;>>> ibatis oracle 批量插入配置 <!--批量新增--><insert id"CreateLawStatisticsClassifyBatch" parameterClass"ArrayList">insert into T_LAW_STATISTICS_CLASSIFY(ID,TEMPLATE,ALIA…...

    2023/3/16 5:39:32
  9. secureCRT免密码登陆Linux

    转自&#xff1a;http://blog.csdn.net/wangquannetwork/article/details/46062675 1.实现原理&#xff1a; 通过CRT生成的密钥对&#xff0c;把公钥上传到Linux服务器指定用户下的.ssh目录中&#xff0c;在客户端上只需输入秘钥的密码即可登陆&#xff0c;而且验证一次以后可以…...

    2023/3/16 11:10:31
  10. PP代码生成器(二) 解决方案, 生成任务, 辅助设计面板

    我们接着上一篇博客继续讨论如何使用PP生成代码. 首先, 我们介绍两个概念”解决方案”和 “生成任务”. 解决方案: 解决方案是一系列生成任务的集合. 它包含若干个生成任务.生成任务: 每个任务会关联一个freemarker模板, 最终会使用这个模板来生成一个结果文件解决方案和任务的…...

    2023/3/16 10:41:54
  11. 函数的运用二(一个一个字读,便于学会机率)

    看完前篇的函数运用是不是不在疑惑&#xff0c;那么下面就来点复杂一点的&#xff0c;也不难的。 如下图所示&#xff1a;读绿色和黄色注释。 是不是能写出来了&#xff0c;调用函数的方式&#xff0c;都是一样的。跟上面前篇的调用几乎一样的&#xff0c;不同就是函数名不同而…...

    2023/3/24 2:33:26
  12. 困扰你的Git操作?

    前端学习笔记篇之git那些事 Git是一款免费、开源的分布式版本控制系统&#xff0c;用于敏捷高效地处理任何或小或大的项目。学习前端&#xff0c;离不开Git的使用&#xff0c;面试时也是一个常考的话题&#xff0c;在日常开发中&#xff0c;也困扰我们许久&#xff0c;下面就让…...

    2023/3/24 2:33:28
  13. ArrayList和LinkedList的区别

    2019独角兽企业重金招聘Python工程师标准>>> ArrayList和Vector使用了数组的实现&#xff0c;可以认为ArrayList或者Vector封装了对内部数组的操作&#xff0c;比如向数组中添加&#xff0c;删除&#xff0c;插入新的元素或者数据的扩展和重定向。 LinkedList使用了…...

    2023/3/16 17:29:27
  14. Winform开发框架之客户关系管理系统(CRM)的开发总结系列2-基于框架的开发过程...

    在上篇随笔《Winform开发框架之客户关系管理系统(CRM)的开发总结系列1-界面功能展示》中介绍了我的整个CRM系统的概貌&#xff0c;本篇继续本系列的文章&#xff0c;介绍如何基于我的《winform开发框架》的基础上进行CRM系统模块的开发工作&#xff0c;希望对大家在系统模块开发…...

    2023/3/16 5:37:14
  15. shell 日期加减运算

    比如今日是2012-04-22$ date -d "1 day" %Y-%m-%d2012-04-23$ date -d "-1 day" %Y-%m-%d2012-04-21$ date -d "2012-04-10 -1 day " %Y-%m-%d2012-04-09$ date -d "2012-04-10 1 day " %Y-%m-%d2012-04-11$ date -d "-1 week &q…...

    2023/3/15 19:12:30
  16. PHP 字符串替换 substr_replace 与 str_replace 函数

    PHP 字符串替换 用于从字符串中替换指定字符串。 相关函数如下&#xff1a; substr_replace()&#xff1a;把字符串的一部分替换为另一个字符串 str_replace()&#xff1a;使用一个字符串替换字符串中的另一些字符substr_replace() substr_replace() 函数用于把字符串的一部分替…...

    2023/3/16 12:34:47
  17. Android开发者指南(12) —— Android Supported Media Formats

    本文档描述了Android平台支持的媒体播放解码器、网络协议。 作为一名应用软件开发者&#xff0c;你可以自由使用平台上的媒体解码器&#xff0c;这些编解码可以是平台提供&#xff0c;或者是特定设备支持。然而&#xff0c;最好习惯于使用媒体编码配置信息使得应用软件代码编写…...

    2023/3/16 12:06:17
  18. Quartz.NET

    概述 Quartz.NET是一个开源的作业调度框架&#xff0c;非常适合在平时的工作中&#xff0c;定时轮询数据库同步&#xff0c;定时邮件通知&#xff0c;定时处理数据等。 Quartz.NET允许开发人员根据时间间隔&#xff08;或天&#xff09;来调度作业。它实现了作业和触发器的多对…...

    2023/3/16 11:38:32
  19. java算法-递归算法

    2019独角兽企业重金招聘Python工程师标准>>> 不废话直接上代码 public class maxtest {public static void main(String[] args) {//###################阶乘递归算法start###################//System.out.println(f(5));//###################阶乘递归算法start##…...

    2023/3/16 11:09:32
  20. Lifecycle-library-stable

    Google 最近发布了稳定Lifecyclelibrary。笔者认为&#xff1a;如果你正在使用alpha或者beta版本&#xff0c;以下内容可能对你有用。 Deprecated LifecycleActivity 在stable version 1.0.0 之前&#xff0c;LifeCycle Library 并没有实现 LifecycleOwner这个接口&#xff0c;…...

    2023/3/16 10:41:08
  21. 数据结构——哈希表

    前言 使用哈希表可以进行非常快速的查找操作。但是&#xff0c;哈希表究竟是什么玩意儿&#xff1f;很多人避而不谈&#xff0c;虽然知道经常用到&#xff0c;很多语言的内置数据结构像python中的字典&#xff0c;java中的HashMap&#xff0c;都是基于哈希表实现。但哈希表究竟…...

    2023/3/16 10:14:40
  22. Bootstrap~Panel和Table

    在我们对一个页面进行设计时&#xff0c;分块是必须的&#xff0c;没有一个网站是一栏而下的&#xff0c;除非你是在看小说&#xff0c;否则你的页面设计一定是分块的&#xff0c;即它由于多个panel组件&#xff0c;在bootstrap里叫到栅格系统&#xff0c;而在每行每列进行宏观…...

    2023/3/16 6:40:03
  23. pyspider操作千万级库,pyspider在对接量级较大库的策略

    pyspider操作千万级库&#xff0c;pyspider在对接量级较大库的策略 如果是需要pyspider正常的流程去执行&#xff0c;那必然是会在on_strat()时任务执行超时&#xff0c;可能只读取出几万条或十几万条数据就会被破终止&#xff0c;然后执行index_page()&#xff0c;由于这个超时…...

    2023/3/16 6:09:47
  24. Js+MVC~公用API的设计,返回jsonp后使ajax的error属性生效!

    相关知识说明 项目用公用的&#xff21;&#xff30;&#xff29;事实上就是其它子项目&#xff0c;包括非子项目需要从这个项目中得到一个公用的信息&#xff0c;这种产生信息的接口我们称为公用的&#xff21;&#xff30;&#xff29;(application program interface)&#…...

    2023/3/16 8:48:42
  25. 【CentOS 7笔记51】,screen虚拟终端#171207

    2019独角兽企业重金招聘Python工程师标准>>> hellopasswd screen工具 为了不让一个任务意外终端nohup command &screen是一个虚拟终端yum install -y screenscreen直接回车就进入了虚拟终端ctral a组合键再按d退出虚拟终端&#xff0c;但不是结束screen -ls查看…...

    2023/3/16 0:46:40
  26. 行内元素和块级元素(转)

    行内元素和块级元素 2013-01-05 11:40 by greenal, 88623 阅读, 3 评论, 收藏, 编辑 1 块级元素&#xff1a;div , p , form, ul, li , ol, dl, form, address, fieldset, hr, menu, table行内元素&#xff1a;span, strong, em, br, img , input, label…...

    2023/3/16 12:33:43
  27. 微信JSApi支付~坑和如何填坑

    微信一直用着不爽&#xff0c;这几天研究它的jsapi支付&#xff0c;即在微信内打开H5页面&#xff0c;完成支付的过程&#xff0c;在这个过程中&#xff0c;你将会遇到各种各样的问题&#xff0c;而大叔将把这些问题的解决方法写一下&#xff0c;希望可以给你带来帮助&#xff…...

    2023/3/16 12:05:20
  28. 阿里云ECS服务器Linux环境下配置php运行环境

    阿里云ECS服务器Linux环境安装配置PHP的运行环境&#xff0c;不同于window操作系统下配置&#xff0c;因为是linux操作系统主要是在命令窗体里输入命令来操作&#xff0c;对于初次接触过linux系统的可能会有点怕怕的&#xff0c;下不去手。。。。。。 需要安装的软件有Apacheph…...

    2023/3/16 0:45:51
  29. vim文本编辑器和yum的搭建

    rpm -ivh 软件名-版本信息-.rpm &#xff08;安装软件&#xff09; rpm -q 软件名 (查看软件是否安装) rpm -e 软件名 &#xff08;卸载转件&#xff09; 因为rpm有依赖关系而yum刚好解决此问题 使用vim创建/修改文本文件 vim文本编辑器 命…...

    2023/3/16 13:02:32
  30. sql developer 连接oracle错误一例(ORA-12505)

    Oracle安装于VM中用sql developer连接oracle报ORA-12505再三检查lsnrctl status&#xff0c;不得正常后来再发现是oracle instance没有启动。转载于:https://blog.51cto.com/9882derek/2049088...

    2023/3/16 13:02:32

最新文章

  1. next_permutation和prev_permutation

    https://blog.csdn.net/c18219227162/article/details/50301513 一&#xff1a;头文件 algorithm 二&#xff1a;具体讲解&#xff1a; 比如我输入一个数组a[3]{1,3,2} 先sort排序,然后next_permutation(a,a3)就是将数组a里面的元素按照比{1,2,3}排序稍大的一号即是1,3,2排序…...

    2023/3/28 16:58:33
  2. 原来java这么危险!

    注&#xff1a;本文源代码点此下载 闲来无事,又开始翻阅java的有关书籍。看到讲访问权限控制的地方的时候,有一句话大概是这个意思不要轻易返回对私有对象的引用。刚开始的时候,我还不以为意,谁会这么做啊,这不等于把私有对象的控制权交出去了吗?但是当我想到,java对一切的传递…...

    2023/3/28 16:58:32
  3. 牛客24 凤凰——并查集(找规律)

    https://www.nowcoder.com/acm/contest/157/B 就是找1的最大个数的树枝 #include <iostream> #include <cmath> using namespace std; int flag[100];//假设其为根节点&#xff0c;1 int t[100];//作为并查集 int find(int x) { if(xt[x]) ret…...

    2023/3/28 16:58:31
  4. AJAX / AJAX框架 / AJAX.NET (Professional) / ASP.NET AJAX

    注&#xff1a;本文源代码点此下载 学习或者研究一个东西,前提至少得先明白它是一个什么东西。 用过ajaxpro,了解过asp.net ajax,最近在学习jquery,为了理清楚这些东西之间的关系和区别,到网上找了点资料,发现园子里“老赵”作了解释,下面的一段就摘自其中。原文:觉得有必要来…...

    2023/3/28 16:58:31
  5. 写学生管理系统的收获

    学生管理系统: 一&#xff1a;遇到的问题收获的小知识点&#xff1a; 一&#xff1a;改变窗口的大小和颜色&#xff1a; *system函数的头文件#include <stdlib.h> *system("color 颜色参数") 改变屏幕窗口的背景色和文字颜色。颜色属性由两个十六进制数字…...

    2023/3/28 16:58:30
  6. delphi 通过线程实现Windows服务

    注&#xff1a;本文源代码点此下载 刷新评论列表刷新页面返回页首 发表评论 昵称: [登录] [注册] 主页: 邮箱:(仅博主可见) 验证码:看不清。 换一个 评论内容: 记住我的昵称和主页 --> 登录注册 [使用ctrlenter键快速提交评论] 0 1314115 tywt0bz0gos…...

    2023/3/28 16:58:30
  7. 用函数完成两个数相加(用两个方法实现)

    用函数完成两个数相加 1. 方法一 int f1(int *x,int *y)//声明函数、定义函数 {int z;z*x*y;return z; } #include<stdio.h> main() { int a,b; printf("请输入两个数&#xff1a;"); scanf("%d,%d",&a,&b);//从键盘输入两个整数 int *x…...

    2023/3/28 16:58:30
  8. ASP.NET AJAX客户端编程之旅(七)——剩下的问题(完结篇)

    注&#xff1a;本文源代码点此下载 asp.net ajax客户端编程之旅(七)——剩下的问题(完结篇) 2008-09-23 11:18 by t2噬菌体, 3345 visits, 收藏, 编辑 摘要 通过前面几篇文章,相信大家对asp.net ajax框架的客户端编程已经有了一定了解。并且通过一个完整的控件开发,对…...

    2023/3/28 16:58:29
  9. 在main函数实现两个数的输入并用函数实现两个数的值相换(两种方法实现)

    在main函数实现两个数的输入并用函数实现两个数的值相换 1. 方法一 void f(int *x,int *y)//定义、声明函数 {int t;//临时变量 t*x;*x*y;*yt;//关于汉诺塔这个是最简单的算法 } #include<stdio.h> main() {int a,b;printf("输入两个数&#xff1a;");scan…...

    2023/3/28 16:58:28
  10. 字符集UTF-8

    怎样解决打开html文件后&#xff0c;里面的汉字变成乱码的的问题&#xff1f; 用Nodepad写html文本的时候&#xff0c;一般默认的是用UTF-8的characterset,国标简体是GB2312。国内的网站的一般都装了中文简体&#xff0c;但是国外的没有安装&#xff0c;所以他们打开你的网页可…...

    2023/3/28 16:58:28
  11. AJAX Control Toolkit tabs 的纯Javascript演示

    注&#xff1a;本文源代码点此下载 ajax control toolkit tabs 的纯javascript演示 本文纯为大家好好学习ajax controltoolkit而写,有不到之处希望大家提出,以免遗祸 众人 标签零 标签一 标签二 标签三 1 11 111 1111 11111 2 22 222 2222 22222 3 33 333 3…...

    2023/3/28 16:58:27
  12. python:编写程序,输入一批学生的成绩,求平均成绩和最高分。

    n1 max_score0 score_sum0 while n < 6:n 1student_Id input(请输入编号&#xff1a; )#编号输入score eval(input(请输入成绩&#xff1a; ))#成绩输入score_sum score#输入成绩的和average_score score_sum / n#平均成绩if score > max_score:max_score score pr…...

    2023/3/28 16:58:27
  13. BFS 走出迷宫 我的第一道BFS

    用S表示出发点&#xff0c;用.表示可以走的点&#xff0c;用G表示最后的终点&#xff0c;用#表示墙&#xff0c;不能通过。计算出能不走出迷宫&#xff0c;如果能走出迷宫&#xff0c;就计算出最短路径。 用队列的思想来实现BFS ***用一个dis[][]二维数组在dis[x][y]处专门存…...

    2023/3/28 16:58:27
  14. Delphi中MessageBox用法

    注&#xff1a;本文源代码点此下载 消息框是个很常用的控件,属性比较多,本文列出了它的一些常用方法,及指出了它的一些应用场合。 1.最简单用法,不带图形 messagebox(0,不同意,提示,mb_ok); messagebox(0,不同意,提示,mb_okcancel ); 2.警告对话框: messagebox(0,密码不能…...

    2023/3/28 16:58:26
  15. DFS HDU1016 继续加油!

    ***自己打印素数表 ***另外一个很重要的思想就是&#xff1a;递归的时候&#xff0c;如果不能继续了&#xff0c; 就得把之前改变的状态变回来&#xff01; 看了大神的代码&#xff0c;自己照葫芦画瓢。。。 #include <stdio.h> #include <string.h>int visited…...

    2023/3/28 16:58:25
  16. java环境变量的设置

    注&#xff1a;本文源代码点此下载 java环境变量的设置 学了不短一段时间的java,可是在黑窗窗下面还是没有编译过。前两天刚刚装的新系统,今天在看电视的时候突然想到把j2se装上,有时间还可以操练一下java。新版的j2se里java这个命令是不需要设置的,但是javac这个命令还是要设…...

    2023/3/28 16:58:25
  17. POJ3617 字典序

    直接上代码&#xff0c;参考挑战&#xff0c;那个bool lefttrue用的很好&#xff0c;易读懂。 #include <stdio.h> #define bool int #define true 1 #define false 0char str[85]; int main() {int cnt0;int N;scanf("%d",&N);getchar();int i;for(i0;i…...

    2023/3/28 16:58:24
  18. python:输入某一年份 year,编写程序判断 year 是否为闰年。闰年的判断条件是:year 能被 4 整除但不能被 100 整除,或 year 能被 400 整除。

    year eval(input("请输入一个年份&#xff1a;")) if (year % 4 0 and year % 100 !0) or year % 400 0:print("{}是闰年".format(year)) else:print("{}年不是闰年&#xff01;".format(year))执行结果为&#xff1a;...

    2023/3/28 16:58:24
  19. Neither the JAVA_HOME nor the JRE_HOME environment variable is defined

    注&#xff1a;本文源代码点此下载 对于使用ide开发的程序员来讲,并不是所有人都对自己用来吃饭的工具了如指掌。常在阴沟跑,哪能不翻船。为此我把自己使用tomcat/eclipse的一些经验教训整理了一下,会陆续的贴出来,也许会帮到和我遇到同样问题的人。 先讲一个tomcat的问题。很…...

    2023/3/28 16:58:24
  20. HDU 1007 分治

    If not now&#xff0c;When&#xff1f;If not me&#xff0c;Who&#xff1f; 看了别人的代码&#xff0c;感觉又学到了很多东西&#xff0c;本渣渣是第一次接触分治。。。 收获&#xff1a; 1&#xff1a;首先是sort()函数的应用。自己定义排序的大小&#xff0c;cmp和cmp…...

    2023/3/28 16:58:23
  21. 求 1-10 的奇数之积,偶数之和。

    i 1 even_sum0#偶数 odd_sum0#奇数 while i < 10:#循环10次if i % 2 0:even_sum even_sum ielse:odd_sum odd_sum ii 1 print("1~10偶数之和为{}&#xff0c;奇数之和为{}".format(even_sum,odd_sum))执行结果为&#xff1a;...

    2023/3/28 16:58:23
  22. Delphi面向对象学习随笔三:overload与override(转)

    注&#xff1a;本文源代码点此下载 delphi面向对象学习随笔三:overload与override 作者:巴哈姆特 (转载请注明出处并保持完整) 首先,我想单独说明一下overload,为什么呢?因为overload和对象化关联不大,所以,我感觉单独提出来说明比较好。 我们都知道,在pascal语法规则中,同…...

    2023/3/28 16:58:23
  23. HDU1015 dfs

    这道题目的错误找了1天多。。。我真菜 收获&#xff1a; 1&#xff1a;还是dfs的思想&#xff0c;回溯——标记——一直到底——返回及英国——返回成功就结束 返回不成功就褪去标记 2&#xff1a;用了map来将字母转换成对应的数字。 3&#xff1a;直接将输入的字符串str&a…...

    2023/3/28 16:58:22
  24. python:从键盘输入学生的成绩,转换成 5 个等级输出。A(90~100),B(80~89),C(70~79),D(60~69),E(0~59)。试用嵌套分支结构实现。

    grades eval(input("请输入你的成绩&#xff1a;")) if 90 < grades < 100:print("A") elif 80 < grades < 90:print("B") elif 70 < grades < 79:print("C") elif 60 < grades < 69:print("D") e…...

    2023/3/28 16:58:22
  25. HDU1045 DFS

    思考一定少对着屏幕而是纸张和书本&#xff0c;不然效率会比较的低下。不要听歌&#xff01; 真的是第一次凭着自己且没有看任何的东西做了一道dfs&#xff0c;感动。。。花费两个小时&#xff0c;继续加油鸭 整体收获&#xff1a; 1&#xff1a;还是对特殊情况的处理容易忽…...

    2023/3/28 16:58:21
  26. python:从键盘输入一个字符,判别它是否大写字母,如果是,将它转换成小写字母;如果不是,则不转换。然后输出最后得到的字符。

    letter str(input("请输入一个字母&#xff1a;")) if letter < Z:#凡是小于大写Z的都要转换成小写print("转换小写字母为:", letter.lower())#lower&#xff08;&#xff09;方法可以把大写转换成小写 else:print("转换大写字母为:", lette…...

    2023/3/28 16:58:21
  27. frank.net

    注&#xff1a;本文源代码点此下载 ajax理念的出现,揭开了无刷新更新页面时代的序幕,并有代替传统web开发中采用form(表单)递交方式更新web页面的趋势,可以算是一个里程碑。但ajax都不是适用于所有地方的,它的适用范围是由它的特性所决定的。 举个应用的例子,是关于级联菜单方…...

    2023/3/28 16:58:21
  28. HDU1023 卡特兰数

    http://www.cnblogs.com/kuangbin/archive/2012/03/21/2410516.html 收获&#xff1a; 就是大数有乘法&#xff0c;有除法的处理方式。先解决乘法&#xff0c;后从高位到低位处理除法。可以把每个行数组的第一个值记作长度 做了N个小时&#xff0c;真的快哭了 //去死吧 #i…...

    2023/3/28 16:58:20
  29. 交换python: a、b、c 三个变量的值。首先从键盘输入 a、b、c 三个变量的原值,然后将变量 a 的值赋给 b,将变量 b 的值赋给 c,将变量 c 的值赋给 a。

    a, b, c map(int, input("请输入a、b、c的值&#xff1a;").split())#输入的数由空格分开 print("a{},b{},c{}".format(a,b,c)) a,b,cb,c,a print("a{},b{},c{}".format(a,b,c))执行结果为&#xff1a;...

    2023/3/28 16:58:20
  30. POJ1048 LCS 动态规划

    收获&#xff1a; 1:while里面不写EOF&#xff01;会output time limit 2:放个学习的地方 https://www.cnblogs.com/hapjin/p/5572483.html #include <iostream> #include <cstdio> #include <cstring> using namespace std;const int maxn500; int dp[m…...

    2023/3/28 16:58:19