Android Runtime(ART)虚拟机和Dalvik虚拟机都使用分页(Paging)和内存映射(Memory-mapped file)来管理内存。这意味着应用修改的任何内存,无论修改的方式是分配新对象还是轻触内存映射的页面,都会一直驻留在RAM中,并且无法换出。要从应用中释放内存,只能释放应用保留的对象引用,使内存可供垃圾回收器回收。这种情况有一个例外:对于任何未被修改的内存映射文件(例如:代码),如果系统想要在其他位置使用其内存,可将其从RAM中换出。

垃圾回收

Android Runtime(ART)虚拟机或者Dalvik虚拟机的受管内存环境会跟踪每次内存分配。一旦确定程序不再使用某块内存,它就会将该内存重新释放在堆中,无需程序员进行任何干预,这种回收受管内存环境中的未使用内存的机制称为垃圾回收。垃圾回收有两个目标:在程序中查找将来无法访问的数据对象,并且回收这些对象使用的资源。
Android的堆是分代的,这意味着它会根据分配对象的预期寿命和大小跟踪不同的分配存储分区,例如:最近分配的对象属于新生代,当某个对象保持活动状态达足够长的时间,可将其提升为较老代,然后是永久代。
堆的每一代对相应对象可占用的内存量都有其自身的专用上限。每当一代开始填满时,系统便会执行垃圾回收事件以释放内存。垃圾回收的持续时间取决于它回收的是哪一代对象以及每一代有多少个活动对象。
尽管垃圾回收速度非常快,但是仍然会影响应用的性能。通常情况下,我们无法从代码中控制何时发生垃圾回收事件,系统有一套专门确定何时执行垃圾回收的标准,当满足条件时,系统会停止执行进程并开始垃圾回收。如果在动画或者音乐播放等密集型处理循环过程中发生垃圾回收,则可能会增加处理时间,进而可能会导致应用中的代码执行超出建议的16ms阈值,无法实现高效、流畅的帧渲染。
此外,我们的代码流执行的各种工作可能迫使垃圾回收事件发生得更频繁或者导致其持续时间超过正常范围,例如:我们在Alpha混合动画的每一帧期间,在for循环的最内层分配多个对象,则可能在堆中创建大量的对象,在这种情况下,垃圾回收器会执行多个垃圾回收事件,并可能降低应用的性能。

共享内存

为了在RAM中容纳所需的一切,Android会尝试跨进程共享RAM页面,它可以通过以下方式实现:
每个应用进程都从一个名为Zygote的现有进程分叉(fork)。系统启动并加载通用框架(Framework)代码和资源(例如:Activity主题背景)时,Zygote进程随之启动。为启动新的应用进程,系统会分叉(fork)Zygote进程,然后在新进程中加载并运行应用代码,这种方法可以让框架(Framework)代码和资源分配的大多数RAM页面在所有应用进程之间共享。
大多数静态数据会内存映射到一个进程中,这种方法使得数据不仅可以在进程之间共享,还可以在需要时换出。静态数据示例包括:Dalvik代码(通过将其放入预先链接的.odex文件中进行直接内存映射)、应用资源(通过将资源表格设计为可内存映射的结构以及通过对齐APK的zip条目)和传统项目元素(例如:.so文件中的原生代码)。
在很多地方,Android使用明确分配的共享内存区域(通过ashmem或者gralloc)在进程间共享同一动态RAM。例如:窗口surface使用在应用和屏幕合成器之间共享的内存,而光标缓冲区则使用在内容提供器和客户端之间共享的内存。

分配与回收内存的应用

Dalvik堆局限于每个应用进程的单个虚拟内存范围。这定义了逻辑堆大小,该大小可以根据需要增长,但不能超过系统为每个应用定义的上限。
堆的逻辑大小与堆使用的物理内存量不同。在检查应用堆时,Android会计算按比例分摊的内存大小(PSS)值,该值同时考虑与其他进程共享的脏页和干净页,但其数量与共享该RAM的应用数量成正比。此(PSS)总量是系统认为的物理内存占用量。
Dalvik堆不压缩堆的逻辑大小,这意味着Android不会对堆进行碎片整理来缩减空间。只有当堆末尾存在未使用的空间时,Android才能缩减逻辑堆大小,但是系统仍然可以减少堆使用的物理内存。垃圾回收之后,Dalvik遍历堆并查找未使用的页面,然后使用madvise将这些页面返回给内核,因此大数据块的配对分配和解除分配应该使所有(或者几乎所有)使用的物理内存被回收,但是从较小分配量中回收内存的效率要低很多,因为用于较小分配量的页面可能仍在与其他尚未释放的数据块共享。

限制应用内存

为了维持多任务环境的正常运行,Android会为每个应用的堆大小设置硬性上限。不同设备的确切堆大小上限取决于设备的总体RAM大小。如果应用在达到堆容量上限后尝试分配更多内存,则可能会收到OutOfMemory异常。
在某些情况下,例如:为了确定在缓存中保存多少数据比较安全,我们可以通过调用getMemoryClass()方法查询系统以确定当前设备上确切可用的堆空间大小,这个方法返回一个整数,表示应用堆的可用兆字节数。

切换应用

当用户在应用之间切换时,Android会将非前台应用保留在缓存中。非前台应用就是指用户看不到或者未运行的前台服务(例如:音乐播放)的应用。例如:当用户首次启动某个应用时,系统会为其创建一个进程,但是当用户离开此应用时,该进程不会退出,系统会将该进程保留在缓存中,如果用户稍后返回该应用,系统就会重复使用该进程,从而加快应用切换速度。
如果应用具有缓存的进程并且保留了目前不需要的资源,那么即使用户未使用应用,它也会影响系统的整体性能,当系统资源(例如:内存)不足时,它就会终止缓存中的进程,系统还会考虑终止占用最多内存的进程以释放RAM。
要注意的是,当应用处于缓存中时,所占用的内存越少,就越有可能免于被终止并得以快速恢复,但是系统也可能根据当下的需求不考虑缓存进程的资源使用情况而随时将其终止。

进程间的内存分配

Android平台在运行时不会浪费可用的内存,它会一直尝试利用所有可用的内存。例如:系统会在应用关闭后将其保留在内存中,以便用户快速切回到这些应用,因此,通常情况下,Android设备在运行时几乎没有可用的内存,所以要在重要系统进程和许多用户应用之间正确分配内存,内存管理至关重要。
下面会讲解Android是如何为系统和用户应用分配内存的基础知识和操作系统如何应对低内存情况。

内存类型

Android设备包含三种不同类型的内存:RAM、zRAM和存储器,如下图所示:
在这里插入图片描述
要注意的是,CPU和GPU访问同一个RAM。

  • RAM是最快的内存类型,但其大小通常有限。高端设备通常具有最大的RAM容量。
    zRAM是用于交换空间的RAM分区。所有数据在放入zRAM时会进行压缩,然后在从zRAM向外复制时进行解压缩。这部分RAM会随着页面进出zRAM而增大或者缩小。设备制造商可以设置zRAM大小上限。
    存储器中包含所有持久性数据(例如:文件系统等)和为所有应用、库和平台添加的对象代码。存储器比另外两种内存的容量大得多。在Android上,存储器不像在其他Linux实现上那样用于交换空间,因为频繁写入会导致这种内存出现损坏,并缩短存储媒介的使用寿命。

内存页面

随机存取存储器(RAM)分为多个页面。通常,每个页面为4KB的内存。
系统会将页面视为可用或者已使用。可用的页面是未使用的RAM,已使用的页面是系统目前正在使用的RAM,可以分为以下类别:
缓存页:有存储器中的文件(例如:代码或者内存映射文件)支持的内存。缓存内存有两种类型:
干净页:存储器未经修改的文件副本,可由内核交换守护进程(kswapd)删除以增加可用内存。
脏页:存储器中经过修改的文件副本,允许通过内核交换守护进程(kswapd)或者通过明确使用msync()或munmap()将更改写回存储器中的文件,以增加内存空间。
干净页:存储器中未经修改的文件副本,可由内核交换守护进程(kswapd)删除以增加可用内存。
脏页:存储器中经过修改的文件副本,可由内核交换守护进程(kswapd)移动到zRAM或者在zRAM中进行压缩以增加可用内存。
私有页:由一个进程拥有且未共享。
共享页:由多个进程使用。
匿名页:没有存储器中的文件支持的内存(例如:由设置了MAP_ANONYMOUS标记的mmap()进行分配)。
脏页:可由内核交换守护进程(kswapd)移动到zRAM或者在zRAM中进行压缩以增加可用内存。
要注意的是,干净页包含存在于存储器中文件(或者文件一部分)的精确副本。如果干净页不再包含文件的精确副本(例如:因应用操作所致),则会变成脏页。干净页可以删除,因为始终可以使用存储器中的数据重新生成它们;脏页不可以删除,否则数据将会丢失。

内存不足管理

Android有两种处理内存不足情况的主要机制:内核交换守护进程和低内存终止守护进程。
内核交换守护进程(kswapd)
内核交换守护进程(kswapd)是Linux内核的一部分,用于将已使用内存转换为可用内存。当设备上的可用内存不足时,该守护进程将变为活动状态。Linux内核设有可用内存上下限阈值。当可用内存降至下限阈值以下时,kswapd开始回收内存;当可用内存达到上限阈值时,kswapd停止回收内存。
kswapd可以删除干净页来回收它们,因为这些页面受到存储器的支持且未经修改。如果某个进程尝试处理已删除的干净页,则系统会将该页面从存储器复制到RAM,这个操作成为请求分页。
下图展示的是由存储器支持的干净页已删除:
在这里插入图片描述
kswapd可以将缓存的私有脏页和匿名脏页移动到zRAM进行压缩,这样可以释放RAM中的可用内存(可用页面)。如果某个进程尝试处理zRAM中的脏页,该页面将被解压缩并移回到RAM。如果与压缩页面关联的进程被终止,则该页面将从zRAM中删除。如果可用内存量低于特定阈值,系统会开始终止进程。
下图展示的是脏页被移至zRAM并进行压缩:
在这里插入图片描述
低内存终止守护进程(LMK)
很多时候,内核交换守护进程(kswapd)不能为系统释放足够多的内存。在这种情况下,系统会使用onTrimMemory()方法通知应用内存不足,应该减少其分配量。如果这还不够,Linux内核会开始终止进程以释放内存,它会使用**低内存终止守护进程(LMK)**来执行此操作。
LMK使用一个名为oom_adj_score的内存不足分值来确定正在运行的进程的优先级,以此决定要终止的进程。最高得分的进程最先被终止。后台应用最先被终止,系统进程最后被终止。
下图列出了从高到低的LMK评分类别,评分最高的类别,即第一行中的项目将最先被终止:
在这里插入图片描述
后台应用(Background
apps):之前运行过且当前不处于活动状态的应用。LMK将首先从具有最高oom_adj_score的应用开始终止后台进程。
上一个应用(Previous
app):最近用过的后台应用。上一个应用比后台应用具有更高的优先级(得分更低),因为相比某个后台应用,用户更有可能切换到上一个应用。
主屏幕应用(Home app):这是启动器应用。终止该应用会使壁纸消失。
服务(Services):服务由应用启动,例如:同步或者上传到云端。 可觉察的应用(Perceptible
apps):用户可通过某种方式察觉到的非前台应用,例如:运行一个显示小界面的搜索或者听音乐。 前台应用(Foreground
app):当前正在使用的应用。终止前台应用看起来就像是应用崩溃了,可能会向用户提示设备出了问题。
持久性(服务)(Persisient):这些是设备的核心服务,例如:电话和WLAN。
系统(System):系统进程。这些进程被终止后,手机可能看起来即将重新启动。
原生(Native):系统使用的极低级别的进程,例如:内核交互终止守护线程(kswapd)。
要注意的是,设备制造商可以更改LMK的行为。

限制应用内存

内核会跟踪系统中的所有内存页面。下图展示的是不同进程使用的页面:
在这里插入图片描述
在确定应用使用的内存量时,系统必须考虑共享的页面。访问相同服务或者库的应用将共享内存页面,例如:Google Play服务和某个游戏应用可能会共享位置信息服务,这样便很难确定属于整个服务和每个应用的内存量分别是多少。下图展示的是由两个应用共享的页面(中间):
在这里插入图片描述
如果需要确定应用的内存占用量,可以使用以下任一指标:
常驻内存大小(RSS):应用使用的共享和非共享页面的数量。
按比例分摊的内存大小(PSS):应用使用的非共享页面的数量加上共享页面的均匀分摊数量(例如:如果三个进程共享3MB,则每个进程的PSS为1MB)。
独占内存大小(USS):应用使用的非共享页面数量(不包括共享页面)。
如果操作系统想要知道所有进程使用了多少内存,那么按比例分摊的内存大小(PSS)非常有用,因为页面只统计一次,不过计算需要花很长时间,因为系统需要确定共享的页面以及共享页面的进程数量。常驻内存大小(RSS)不区分共享和非共享页面,因此计算起来更快,更适合跟踪内存分配量的变化。

管理应用内存

随机存取存储器(RAM)在任何软件开发环境中都是一项宝贵资源,尤其是在移动操作系统中,由于物理内存通常都有限,因此RAM就更加宝贵了。虽然Android Runtime(ART)虚拟机和Dalvik虚拟机都执行例行的垃圾回收任务,但这并不意味着我们可以忽略应用分配和释放内存的位置和时间。我们仍然需要避免引入内存泄漏问题**(通常因为在静态成员变量中保留对象引用而引起),并且在适当时间(例如:生命周期回调)释放所有Reference**对象。

监控可用内存和内存使用量

我们需要先找到应用中内存使用问题,然后才能修复问题。可以使用Android Studio中的内存性能剖析器(Memory Profiler)来帮助我们查找和诊断内存问题:
了解我们的应用在一段时间内如何分配内存。Memory Profiler可以显示实时图表,包括:应用的内存使用量、分配的Java对象数量和垃圾回收事件发生的时间。
发起垃圾回收事件,并在应用运行时拍摄Java堆的快照。
记录应用的内存分配情况,然后检查有分配的对象、查看每个分配的堆栈轨迹,并在Android Studio编辑器中跳转到对应的代码。
释放内存以响应事件
如上面所述,Android可以通过多种方式从应用中回收内存或者在必要时完全终止应用,从而释放内存以执行关键任务。为了进一步帮助平衡系统内存并避免系统需要终止我们的应用进程,我们可以在Activity类中实现ComponentCallback2接口并且重写onTrimMemory()方法,就可以在处于前台或者后台时监听与内存相关的事件,然后释放对象以响应指示系统需要回收内存的应用生命周期事件或者系统事件,示例代码如下所示:

fun doSomethingMemoryIntensive() {// 在执行需要大量内存的逻辑之前,检查设备是否处于低内存状态if (!getAvailableMemory().lowMemory) {// 执行需要大量内存的逻辑}
}// 获取设备当前内存状态的MemoryInfo对象
private fun getAvailableMemory(): ActivityManager.MemoryInfo =ActivityManager.MemoryInfo().also {(getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager).getMemoryInfo(it)}

使用内存效率更高的代码结构

我们可以在代码中选择效率更高的方案,以尽可能降低应用的内存使用量。
谨慎使用服务(Service)
如果我们的应用需要某项服务(Service)在后台执行工作,请不要让其保持运行状态,除非它真的需要运行作业,在服务完成任务后应该使其停止运行,否则可能会导致内存泄漏。
在我们启动某项服务后,系统更倾向于让此服务的进程始终保持运行状态,这种行为会导致服务进程代价十分高昂,因为一旦服务使用了某部分RAM,那么这部分RAM就不再供其他进程使用,这样会减少系统可以在LRU缓存中保留的缓存进程数量,从而降低应用切换效率。当内存紧张,并且系统无法维护足够的进程以托管当前运行的服务时,就可能导致内存抖动。
通常应该避免使用持久性服务,因为它们会对可用内存提出持续性的要求,我们可以使用JobScheduler调度后台进程。
如果我们必须使用某项服务,则限制此服务的生命周期的最佳方式是使用IntentService,它会在处理完启动它的intent后立即自行结束。
使用经过优化的数据容器
编程语言所提供的部分类并未针对移动设备做出优化,例如:常规HashMap实现的内存效率可能十分低下,因为每个映射都需要分别对应一个单独的条目对象。
Android框架包含几个经过优化的数据容器,例如:SparseArray、SparseBooleanArray和LongSparseArray,以SparseArray为例,它的效率更高,因为它可以避免系统需要对键(有时还对值)进行自动装箱(这会为每个条目分别创建1~2个对象)。
根据业务需要,尽可能使用精简的数据结构,例如:数组。
谨慎对待代码抽象
开发者往往会将抽象简单地当做一种良好的编程做法,因为抽象可以提高代码灵活性和维护性,不过抽象的代价很高,通常它们需要更多的代码才能执行,需要更多的时间和更多的RAM才能将代码映射到内存中,因此,如果抽象没有带来显著的好处时,我们就应该避免使用抽象。
针对序列化数据使用精简版Protobuf
协议缓冲区(Protocol Buffers)是Google设计的一种无关语言和平台并且可扩展的机制,用于对结构化数据进行序列化,它与XML类似,但是更小、更快也更简单。在移动端中使用精简版的Protobuf,因为常规Protobuf会生成极其冗长的代码,这会导致应用出现各种问题:例如:RAM使用量增多、APK大小显著增加和执行速度变慢。
避免内存抖动
如前面所述,垃圾回收事件通常不会影响应用的性能,不过如果在短时间内发生许多垃圾回收事件,就可能会快速耗尽帧时间,系统花在垃圾回收上的时间越多,能够花在呈现界面或者流式传输音频等其他任务上的时间就越少。
通常,内存抖动可能会导致出现大量的垃圾回收事件,实际上,内存抖动可以说明在给定时间内出现的已分配临时对象的数量,例如:我们在for循环中分配多个临时对象或者在View的onDraw()方法中创建Paint对象或者Bitmap对象,在这两种情况下,应用都会快速创建大量对象,这些操作可以快速消耗新生代(young generation)区域中的所有可用内存,从而迫使垃圾回收事件发生。
我们可以借助Android Studio中内存性能剖析器(Memory Profiler)找到内存抖动较高的位置,确定代码中问题区域后,尝试减少对性能至关重要的区域中的分配数量,可以考虑将某些代码逻辑从内部循环中移出或者使用工厂方法模式。

移除占用大量内存的资源和库

代码中的某些资源和库可能会在我们不知情的情况下吞噬内存,APK的总体大小(包括第三方库或者嵌入式资源)可能会影响应用的内存消耗量,我们可以通过从代码中移除任何冗余、不必要或者臃肿的组件、资源或者库,降低应用的内存消耗量。
缩减总体APK大小
我们可以通过缩减应用的总体大小来显著降低应用的内存使用量。位图(bitmap)大小、资源、动画帧数和第三方库都会影响APK的大小。Android Studio和Android SDK提供了帮助我们缩减资源和外部依赖项大小的多种工具,这些工具可以缩减代码,例如:R8编译。
当我们使用Android Gradle插件3.4.0版本及更高版本构建项目时,这个插件不再使用ProGuard来执行编译时代码优化,而是与R8编译器协同工作来处理以下编译时任务:
代码缩减(即摇树优化(Tree Shaking)):从应用及其库依赖项中检测并安全地移除未使用的类、字段、方法和属性(这使其成为了一个对于规避64K引用限制非常有用的工具)。例如:如果我们仅使用某个库依赖项的少数几个API,缩减功能可以识别应用未使用的库代码,并且从应用中移除这部分代码。
资源缩减:从封装应用中移除不使用的资源,包括应用库依赖项中不使用的资源,这个功能可以与代码缩减功能结合使用,这样一来,移除不使用的代码后,也可以安全地移除不再引用的所有资源。
混淆处理:缩短类和成员的名称,从而减少DEX文件的大小。
优化:检查并重写代码,以进一步减少应用的DEX文件的大小。例如:如果R8检测到从未使用过某段if/else语句的else分支的代码,则会移除else分支的代码。
使用Android App Bundle上传应用(仅限于Google Play)
要在发布到Google Play时立即缩减应用大小,最简单的方法就是将应用发布为Android App Bundle,这是一种全新的上传格式,包含应用的所有编译好的代码和资源,Google Play负责处理APK生成和签名工作。
Google Play的新应用服务模式Dynamic Delivery会使用我们提供的App Bundle针对每位用户的设备配置生成并提供经过优化的APK,因此他们只需下载运行我们的应用所需的代码和资源,我们不需要再编译、签署和管理多个APK以支持不同的设备,而用户也可以获得更小、更优化的下载文件包。
要注意的是,Google Play规定我们上传的签名APK的压缩下载大小限制为不超过100MB,而对使用App Bundle发布的应用压缩下载大小限制为150MB。
使用Android Size Analyzer
Android Size Analyzer工具可让我们轻松地发现和实施多种缩减应用大小的策略,它可以作为Android Studio插件或者独立JAR使用。
在Android Studio中使用Android Size Analyzer
我们可以使用Android Studio中的插件市场下载Android Size Analyzer插件,可以按着以下步骤操作:
依次选择Android Studio>Preferences,如果是Windows的话,依次选择File>Settings。
选择左侧面板中的Plugins部分。
点击Marketplace标签。
搜索Android Size Analyzer插件。
点击分析器插件的Install按钮。
如下图所示:
在这里插入图片描述
安装插件后,从菜单栏依次选择Analyze>Analyze App Size,对当前项目运行应用大小分析,分析了项目后,系统会显示一个工具窗口,其中包含有关如何缩减应用大小的建议,如下图所示:
在这里插入图片描述
通过命令行使用分析器
我们可以从GitHub以TAR或者ZIP文件形式下载最新版本的Android Size Analyer,解压缩文件后,使用以下某个命令对Android项目或者Android App Bundle运行size-analyzer脚本(在Linux或者MacOS上)或者size-analyzer.bat脚本(在Windows上):

./size-analyzer check-bundle <path-to-aab>
./size-analyzer check-project <path-to-project-directory>

了解APK结构
在讨论如何缩减应用的大小之前,有必要了解下APK的结构。APK文件由一个Zip压缩文件组成,其中包含构成应用的所有文件,这些文件包括Java类文件、资源文件和包含已编译资源的文件。
APK包含以下文件夹:
META-INF/:包含CERT.SF和CERT.RSA签名文件,以及MANIFEST.MF清单文件。
assets/:包含应用的资源,可以使用AssetManager对象检索这些资源。
res/:包含未编译到resources.arsc中的资源。
lib/:包含特定于处理器软件层的已编译代码。这个目录包含每种平台类型的子目录,例如:armeabi、armeabi-v7a、arm64-v8a、x86、x86_64和mips。
APK还包含以下文件,在这些文件中,只有AndroidManifest.xml是必需的:
resources.arsc:包含已编译的资源,这个文件包含res/values/文件夹的所有配置中的XML内容。打包工具会提取此XML内容,将其编译成二进制文件形式,并压缩内容,这些内容包括语言字符串和样式,以及未直接包含在resources.arsc文件中的内容(例如:布局文件和图片)的路径。
classes.dex:包含以Android Runtime(ART)虚拟机和Dalvik虚拟机可理解的DEX文件格式编译的类。
AndroidManifest.xml:包含Android清单文件,这个文件列出了应用的名称、版本、访问权限和引用的库文件,它使用了Android的二进制XML格式。
缩减资源数量和大小
APK的大小会影响应用加载速度、使用的内存量和消耗的电量。缩减APK大小的一种简单方法是缩减其包含的资源数量和大小,具体来说,我们可以移除应用不再使用的资源,并且可以用可伸缩的Drawable对象取代图片文件。
移除未使用的资源
lint工具是Android Studio中附带的静态代码分析器,可以检测到res/文件夹中未被代码引用的资源,当lint工具发现项目中有可能未使用的资源时,会显示一条消息,消息如下所示:

res/layout/preferences.xml: Warning: The resource R.layout.preferences appearsto be unused [UnusedResources]

要注意的是,lint工具不会扫描assets/文件夹、通过反射引用的资源和已链接至应用的库文件,此外,它不会移除资源,只会提醒我们它们的存在。
如果我们在应用的build.gradle文件中启用了shrinkResource,那么Gradle可以帮我们自动移除未使用的资源,示例代码如下:

android {buildTypes {release {minifyEnabled trueshrinkResources trueproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}}
}

要使用shrinkResource,我们必须启用代码缩减功能,在编译过程中,R8首先会移除未使用的代码,然后Android Gradle插件会移除未使用的资源。
在Android Gradle插件0.7版本及更高版本中,我们可以声明应用支持的配置。Gradle会使用resConfig和resConfigs变体以及defaultConfig选项将这些信息传递给编译系统,随后,编译系统会阻止来自其他不受支持配置的资源出现在APK中,从而缩减APK的大小。
要注意的是,代码缩减可以清理库的一些不必要代码,但可能无法移除大型内部依赖项。
尽量减少库中的资源使用量
在开发Android应用时,我们通常需要使用外部库来提高应用的可用性和多功能性,例如:我们可以使用Glide来实现图片加载功能。
如果库是为服务器或者桌面设备设计的,则它可能包含应用不需要的许多对象和方法,如果库许可允许我们修改库,我们可以编辑库的文件来移除不需要的部分,我们还可以使用适合移动设备的库。
仅支持特定密度
Android支持多种设备,涵盖了各种屏幕密度。在Android 4.4(API级别19)及更高版本中,框架支持各种密度:ldpi、mdpi、tvdpi、hdpi、xhdpi、xxhdpi和xxxhdpi。尽管Android支持所有这些密度,但是我们无需将光栅化资源导出为每个密度。
如果我们不添加用于特定屏幕密度的资源,Android会自动缩放为其他屏幕密度设计的资源,建议每个应用至少包含一个xxhdpi图片变体。
使用可绘制对象
某些图片不需要静态图片资源,框架可以在运行时动态绘制图片。我们可以使用Drawable对象(XML中的shape元素)来动态绘制图片,它只会占用APK中的少量空间,此外,XML的Drawable对象可以生成符合Material Design准则的单色图片。
重复使用资源
我们可以为图片的变体添加单独的资源,例如:同一图片经过色调调整、阴影设置或者旋转的版本。建议重复使用同一组资源,并在运行时根据需要对其进行自定义。
在Android5.0(API级别21)及更高版本上,使用android:tint和android:tintMode属性可以更改资源的颜色,对于较低版本的平台,则使用ColorFilter类。
我们可以省略仅是另一个资源的旋转等效项的资源,下面例子展示了通过绕图片中心位置旋转180度,将拇指向上变成拇指向下,示例代码如下所示:

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"android:drawable="@drawable/ic_thumb_up"android:fromDegrees="180"android:pivotX="50%"android:pivotY="50%" />

从代码进行渲染
我们可以通过按一定程序渲染图片来缩减APK大小,这样可以释放不少空间,因为不需要在APK中存储图片文件。
压缩PNG文件
aapt工具可以在编译过程中通过无损压缩来优化放置在res/drawable/中的图片资源,例如:aapt工具可以通过调色板将不需要超过256种颜色的真彩色PNG转换为8位PNG,这样做会生成质量相同但内存占用量更小的图片。
要注意的是,aapt工具具有以下限制:
aapt工具不会缩减asset/文件夹中包含的PNG文件。
图片文件需要使用256种或更少的颜色才可供aapt工具进行优化。
aapt工具可能会扩充已压缩的PNG文件,为防止出现这种情况,我们可以在Gradle中使用cruncherEnabled标记为PNG文件停用此过程,示例代码如下:

aaptOptions {cruncherEnabled = false
}

压缩PNG和JPEG文件
我们可以使用pngcrush、pngquant或者zopflipng等工具缩减PNG文件的大小,同时不损失画质。所有这些工具都可以缩减PNG文件的大小,同时保持肉眼感知的画质不变。
pngcrush工具是最有效的:该工具会迭代PNG过滤器和zlib(Deflate)参数,使用过滤器和参数的每个组合来压缩图片,然后它会选择可产生最小压缩输出的配置。
要压缩JPEG文件,我们可以使用packJPG和guetzli等工具。
使用WebP文件格式
如果以Android3.2(API级别13)及更高版本为目标(target),我们可以使用WebP文件格式的图片代替PNG文件或者JPEG文件。WebP格式提供有损压缩(例如:JPEG)和透明度(例如:PNG),不过与PNG或者JPEG相比,这种格式可以提供更好的压缩效果。
我们可以使用Android Studio将现有的BMP、JPG、PNG或者静态GIF图片转换成WebP格式。
要注意的是,Google Play只接受PNG格式的启动器图标。
使用矢量图形
我们可以使用矢量图形创建与分辨率无关的图标和其他可伸缩媒体,它可以极大地减少APK占用的空间。矢量图片在Android中以VectorDrawable对象的形式表示,100字节的文件可以生成与屏幕大小相同的清晰图片。
要注意的是,系统渲染每个VectorDrawable对象需要花费大量时间,使用VectorDrawable对象渲染较大的图片需要更长的时间才能显示在屏幕上,因此建议在显示小图片时才使用VectorDrawable对象。
将矢量图形用于动画图片
请勿使用AnimationDrawable创建逐帧动画,因为这样做需要为动画的每个帧添加单独的位图(bitmap)文件,而这样做就会大大增加APK的大小,应该改为使用AnimatedVectorDrawableCompat创建动画矢量可绘制资源。
减少原生(Native)和Java代码
我们可以使用多种方法来缩减应用中的原生(Native)和Java代码库的大小。
移除不必要的生成代码
确保了解自动生成任何代码所占用的空间,例如:许多协议缓冲区工具会生成过多的类和方法,这可能会使应用的大小增加一倍或者两倍。
避免使用枚举
单个枚举会使应用的classes.dex文件增加大约1.0到1.4KB的大小,这些增加的大小会快速累积,产生复杂的系统或者共享库,如果可能,请考虑使用@IntDef注解和代码缩减移除枚举并将它们转换为整数,此类型转换可保留枚举的各种安全优势。
缩减原生二进制文件的大小
如果我们的应用使用原生代码和Android NDK,我们还可以通过优化代码来缩减发布版应用的大小,移除调试符号和避免解压缩原生库是两项很实用的技术。
移除调试符号
如果应用正在开发中且仍需要调试,则使用调试符号非常合适,我们可以使用Android NDK中提供的arm-eabi-strip工具从原生库中移除不必要的调试符号,之后,我们就可以编译发布版本。
避免解压缩原生库
在构建应用的发布版本时,我们可以通过在应用清单的application元素中设置android:extractNativeLibs=“false”,将未压缩的.so文件打包在APK中。停用此标记可防止PackageManager在安装过程中将**.so文件从APK复制到文件系统**,并具有减少应用更新的额外好处。使用Android Gradle插件3.6.0版本及更高版本构建应用时,插件会默认将此属性设为false。
维护多个精简APK
APK可能包含用户下载但从不使用的内容,例如:其他语言或者针对特定屏幕密度的资源。要确保为用户提供最小的下载文件,我们应该使用Android App Bundle将应用上传到Google Play。通过上传App Bundle,Google Play能够针对每位用户的设备配置生成并提供经过优化的APK,因此用户只需下载运行我们的应用所需的代码和资源,我们无需再编译、签署和管理多个APK以支持不同的设备,而用户也可以获得更小、更优化的下载文件包。
如果我们不打算将应用发布到Google Play,则可以将应用细分为多个APK,并按屏幕尺寸或者GPU纹理支持等因素进行区分。
当用户下载我们的应用时,我们的设备会根据设备的功能和设置接收正确的APK,这样的话设备就不会接收设备所不具备的功能和资源,例如:如果用户具有hdpi设备,则不需要为更高密度显示器提供的xxxhdpi资源。
使用Dagger2实现依赖注入
依赖注入框架可以简化我们编写的代码,并提供一个可供我们进行测试及其他配置更改的自适应环境。
如果我们打算在应用中使用依赖注入框架,请考虑使用Dagger2。Dagger2不使用反射来扫描应用的代码,它的静态编译时实现意味着它可以在Android应用中使用,而不会带来不必要的运行时代价或者内存消耗量。
其他使用反射的依赖注入框架倾向于通过扫描代码中的注释来初始化进程,这个过程可能需要更多的CPU周期和RAM,并可能在应用启动时导致出现明显的延迟。
谨慎使用外部库
外部库代码通常不是针对移动环境编写的,在移动客户端上运行可能效率低下。如果我们决定使用外部库,则可能需要针对移动设备优化该库,在决定使用该库之前,请提前规划,并在代码大小和RAM消耗量方面对库进行分析。
即使是一些针对移动设备进行优化的库,也可能因实现方式不同而导致问题,例如:一个库可能使用的是精简版Protobuf,而另一个库使用的是Micro Protobuf,导致我们的应用出现两种不同的Protobuf实现。日志记录、分析、图片加载框架以及许多我们意外之外的其他功能的不同实现都可能导致这种情况。
虽然ProGuard可以使用适当的标记移除API和资源,但是无法移除库的大型内部依赖项。我们所需要的这些库中的功能可能需要较低级别的依赖项。如果存在以下情况,这就特别容易导致出现问题:我们使用某个库中的Activity子类(往往会有大量的依赖项)、**库使用反射(这很常见,意味着我们需要花费大量的时间手动调整ProGuard以使其运行)**等。
此外,请避免针对数十个功能中的一两个功能使用共享库,这样会产生大量我们甚至根本用不到的代码和开销,在考虑是否使用这个库时,请查找与我们的需求十分契合的实现,否则,我们可以决定自己去创建实现。

谭嘉俊的博客地址:
https://juejin.im/user/593f7b33fe88c2006a37eb9b

https://shimo.im/docs/TG8PDh9D96WGTT8W

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. 爬虫学习笔记(一):爬虫介绍

    爬虫学习(一) 爬虫介绍:什么是爬虫 网络爬虫也叫网络蜘蛛,如果把互联网比喻成一个蜘蛛网,那么爬虫就是在网上爬来爬去的蜘蛛,爬虫程序通过请求url地址,根据响应的内容进行解析采集数据。 作用 通过有效的爬虫手段批量采集数据,可以降低人工成本,提高有效数据量,给予运…...

    2024/5/3 3:43:57
  2. Scrapy58同城租房房屋信息(完整)

    Scrapy创建Scrapy项目scrapy startproject mySpider生成一个爬虫scrapy genspider 爬虫名字 "允许爬取网址范围"运行爬虫scrapy crawl 爬虫名字Xpath语法提取元素小编相信你们都会的,在此就放上一个官方文档,有需要便可查看Xpath教程58同城字体加密破解字体加密,一…...

    2024/5/3 5:48:24
  3. C++ day37 标准模板库STL初识

    文章目录简介是什么:容器类模板,迭代器类模板,函数对象模板,算法模板的集合STL不是面向对象编程,而是泛型编程!历史:1994年发布模板类vector示例1:创建vector对象,用[]随机访问元素vector类的方法示例2:演示这些方法STL的非成员函数:也是为了通用性for_each()random…...

    2024/4/15 17:31:08
  4. C++ day30 友元(一)友元类, 友元成员函数

    “友元”就是“朋友”,可能这么翻译显得官方大气一些吧 友元一共有三种:友元函数 友元类 友元成员函数 第一种在这里学了;第二种和第三种在本文学习。注意友元的强大权限:可以从外部访问类的私有部分! 虽然友元的权限有点太大了,都能从外部直接访问类的私有数据了,但是这…...

    2024/4/24 15:37:56
  5. Apollo配置中心架构设计原理

    一、基础模型 1.用户在配置中心对配置进行修改并发布 2.配置中心通知Apollo客户端有配置更新 3.Apollo客户端从配置中心拉取最新的配置、更新本地配置并通知到应用二、架构模块 1、Config Service提供配置的读取、推送等功能,服务对象是Apollo客户端 2、Admin Service提供配置…...

    2024/4/15 17:31:08
  6. C++ day34 异常(三)异常规范,未捕获异常,意外异常,异常导致内存泄漏

    文章目录异常规范(C++98添加,C++11已摒弃,不建议使用)异常规范的作用(正是这俩作用的鸡肋和难办使它失去了粉丝)C++11支持的特殊的异常规范:关键字noexcept(程序员的庄严承诺)异常被引发后可能出现的两种问题未捕获异常 uncaught exception示例意外异常 unexpected ex…...

    2024/4/15 17:31:06
  7. 《python 菜鸟入门》3

    1.数据类型整数型:int型,int类型的值可以是正数可以是负数。浮点型:float型,具有小数部分。 如何判断是整数型还是浮点型? 用python的内置函数 type 形式:type<数>数值操作2.类型转换和舍入转换为int型就是把小数部分丢掉,而不是舍入 四舍五入的方法是round函数。…...

    2024/4/27 21:49:22
  8. 杭电多校2020第四场

    Deliver the Cake 题意: n个地点,m条双向道路,地点的类型分L、R、M三种,到达L点需保持状态L,到达R需保持状态R,到M两种状态都可以,切换状态需要消耗时间x,问s到t点所需最少时间。 题解: 将M类型的点一分为二,1 ~ N所有类型为M的点设为L点,N+1 ~ 2N所有类型为M的点设…...

    2024/4/19 21:17:17
  9. numpy中的vstack和hstack

    numpy中的vstack和hstack vstack和hstack都是numpy中用于合并两个小数组的函数。他们俩不仅名字很像,用法也很像,所以很容易搞混。 首先需要明确几个共性:两个函数都只接收一个参数:vstack(tup)和hstack(tup)。但是,正如前面说到的,这两个函数是用于合并两个数组的,所以…...

    2024/4/15 17:31:03
  10. C++继承

    C++继承 1. 继承相关概念 1.1. 什么是继承继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程…...

    2024/4/15 17:31:01
  11. 乐优商城之商品管理(十一)

    文章目录 (一)商品品牌查询 (二)品牌新增页面 (三)商品新增后台代码 (四)商品编辑的回显 (五)商品更新 (六)部署前台系统 (七)common.js (一)商品品牌查询 我们要根据分类来查询品牌,直接查询品牌的话数量就太多了,要用分类(cid3)进行过滤,如下:/*** 根据分类的id(cid3)…...

    2024/4/26 4:14:54
  12. NLP入门Task5 基于深度学习的文本分类2-3TextRNN

    在datawhale组织的天池大赛学习:入门NLP(以新闻文本分类赛事进行学习)。 目录:一、TextRNN二、baseline三、学习参考笔记 一、TextRNN TextRNN利用RNN(循环神经网络)进行文本特征抽取,由于文本本身是一种序列,而LSTM天然适合建模序列数据。TextRNN将句子中每个词的词向…...

    2024/4/28 6:44:55
  13. 计算机网络——TCP三次握手

    目录TCP连接过程TCP为什么不可以两次握手 TCP连接过程 第一次握手,TCP客户进程A向TCP服务器进程发出连接请求报文段,这时同步位为SYN=1,初始序号seq=x,TCP客户进程进入SYN-SENT(同步已发送)状态。 第二次握手,TCP服务器进程B向TCP客户进程A发送确认报文段,这时同步位SY…...

    2024/4/15 15:25:49
  14. PyTorch学习-多维特征输入

    对糖尿病病人的病情进行预测,预测未来是否会加重。 输入有8个指标,也就是8个维度,输出只有一个维度即是否加重病情。 维度的变化其实就是线性代数中矩阵乘法的作用:[mn]⋅[nk]=[mk][m\times n]\cdot [n\times k]=[m\times k][mn]⋅[nk]=[mk] import numpy as np import tor…...

    2024/5/3 6:03:21
  15. 分布式框架-Dubbo

    分布式框架-Dubbo 1.什么是SOA架构? SOA是Service-Oriented Architecture的首字母简称,它是一种支持面向服务的架构样式。从服务、基于服务开发和服务的结果来看,面向服务是一种思考方式。其实SOA架构更多应用于互联网项目开发。 为什么互联网项目会采用SOA架构呢?随着互联…...

    2024/4/17 8:21:12
  16. 【搭建个人博客】数据库表的设计(三)

    【搭建个人博客】数据库表的设计(三)一、数据表二、实体类关系三、表结构1、博文表(blog)2、博文分类表(blog_type)3、评论表(comment)4、友链表(friendLink)5、留言表(message)6、 用户表(user)7、角色表(user_type)四、建表sql博主用的MySQL8.0数据库,使用m…...

    2024/4/30 23:34:42
  17. flink-scala的wordcount案例(分别用流处理和批处理)

    worldcount样例1.流式2.批处理 1.流式 windows下载netcat,然后配置路径到path 命令行启动nc -l -p 8000监听端口 启动scala程序,代码如下 import org.apache.flink.streaming.api.scala.{DataStream, StreamExecutionEnvironment}object StreamWcApp {//流处理,要往8000端口…...

    2024/4/27 14:29:36
  18. 笨方法学C语言学习笔记(习题1 打开尘封的编译器)

    对书写代码忌讳开两个屏幕直接照抄 另外少用ide学习一门语言 第一个程序 命名为ex1.c #include <stdio.h>/* This is a comment. */ int main(int argc, char *argv[]) {int distance = 100;// this is also a commentprintf("You are %d miles away.\n", dist…...

    2024/4/15 15:25:43
  19. Python——解决 cmd 下 pip 工具版本问题

    pip 版本更新问题黄色提示信息解决方案如下: python -m pip install --upgrade pip -ihttps://pypi.douban.com/simple安装包: pip install 你要的包名 --upgrade pip -ihttps://pypi.douban.com/simplewin下换国内镜像源参考此文章: https://blog.csdn.net/weixin_46313446…...

    2024/4/15 15:25:42
  20. 【转载】thinkphp3.2嵌入百度编辑器ueditor的实例代码

    本篇文章主要介绍了thinkphp3.2嵌入百度编辑器ueditor的实例代码,具有一定的参考价值,有兴趣的可以了解一下本文介绍了thinkphp3.2嵌入百度编辑器ueditor,分享给大家,希望此文章对各位有所帮助因为排版要求,很多时候我们需要嵌入富文本编辑器,输出带html标签的文本内容。…...

    2024/4/18 13:26:16

最新文章

  1. 钉钉手机端调试前端H5项目流程

    此流程以Vue项目为例 一、操作步骤 在根目录下 vue.config.js 文件中将 devServer.host 设置为 0.0.0.0 // vue.config.js module.exports {devServer: {host: 0.0.0.0,...},...}本地启动项目&#xff0c;获取 Network App running at:- Local: http://localhost:8080/ -…...

    2024/5/3 6:33:14
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. 3d representation的一些基本概念

    顶点&#xff08;Vertex&#xff09;&#xff1a;三维空间中的一个点&#xff0c;可以有多个属性&#xff0c;如位置坐标、颜色、纹理坐标和法线向量。它是构建三维几何形状的基本单元。 边&#xff08;Edge&#xff09;&#xff1a;连接两个顶点形成的直线段&#xff0c;它定…...

    2024/5/2 17:20:39
  4. Chrome 浏览器无法保存或自动填充密码

    Chrome 浏览器无法保存或自动填充密码 分类 平时使用 Chrome 浏览器都会对网站的用户名密码自动填充&#xff0c;今天发现突然不行了&#xff0c;找到一个解决办法&#xff1a; 1、退出 Chrome 浏览器。2、打开 Chrome 安装目录下的的 Profile 目录&#xff0c;删除 Login Da…...

    2024/4/30 3:32:50
  5. 416. 分割等和子集问题(动态规划)

    题目 题解 class Solution:def canPartition(self, nums: List[int]) -> bool:# badcaseif not nums:return True# 不能被2整除if sum(nums) % 2 ! 0:return False# 状态定义&#xff1a;dp[i][j]表示当背包容量为j&#xff0c;用前i个物品是否正好可以将背包填满&#xff…...

    2024/5/2 11:19:01
  6. 【Java】ExcelWriter自适应宽度工具类(支持中文)

    工具类 import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet;/*** Excel工具类** author xiaoming* date 2023/11/17 10:40*/ public class ExcelUti…...

    2024/5/2 16:04:58
  7. Spring cloud负载均衡@LoadBalanced LoadBalancerClient

    LoadBalance vs Ribbon 由于Spring cloud2020之后移除了Ribbon&#xff0c;直接使用Spring Cloud LoadBalancer作为客户端负载均衡组件&#xff0c;我们讨论Spring负载均衡以Spring Cloud2020之后版本为主&#xff0c;学习Spring Cloud LoadBalance&#xff0c;暂不讨论Ribbon…...

    2024/5/2 23:55:17
  8. TSINGSEE青犀AI智能分析+视频监控工业园区周界安全防范方案

    一、背景需求分析 在工业产业园、化工园或生产制造园区中&#xff0c;周界防范意义重大&#xff0c;对园区的安全起到重要的作用。常规的安防方式是采用人员巡查&#xff0c;人力投入成本大而且效率低。周界一旦被破坏或入侵&#xff0c;会影响园区人员和资产安全&#xff0c;…...

    2024/5/2 9:47:31
  9. VB.net WebBrowser网页元素抓取分析方法

    在用WebBrowser编程实现网页操作自动化时&#xff0c;常要分析网页Html&#xff0c;例如网页在加载数据时&#xff0c;常会显示“系统处理中&#xff0c;请稍候..”&#xff0c;我们需要在数据加载完成后才能继续下一步操作&#xff0c;如何抓取这个信息的网页html元素变化&…...

    2024/5/2 9:47:31
  10. 【Objective-C】Objective-C汇总

    方法定义 参考&#xff1a;https://www.yiibai.com/objective_c/objective_c_functions.html Objective-C编程语言中方法定义的一般形式如下 - (return_type) method_name:( argumentType1 )argumentName1 joiningArgument2:( argumentType2 )argumentName2 ... joiningArgu…...

    2024/5/2 6:03:07
  11. 【洛谷算法题】P5713-洛谷团队系统【入门2分支结构】

    &#x1f468;‍&#x1f4bb;博客主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 收录于专栏 【洛谷算法题】 文章目录 【洛谷算法题】P5713-洛谷团队系统【入门2分支结构】&#x1f30f;题目描述&#x1f30f;输入格…...

    2024/5/2 9:47:30
  12. 【ES6.0】- 扩展运算符(...)

    【ES6.0】- 扩展运算符... 文章目录 【ES6.0】- 扩展运算符...一、概述二、拷贝数组对象三、合并操作四、参数传递五、数组去重六、字符串转字符数组七、NodeList转数组八、解构变量九、打印日志十、总结 一、概述 **扩展运算符(...)**允许一个表达式在期望多个参数&#xff0…...

    2024/5/2 23:47:43
  13. 摩根看好的前智能硬件头部品牌双11交易数据极度异常!——是模式创新还是饮鸩止渴?

    文 | 螳螂观察 作者 | 李燃 双11狂欢已落下帷幕&#xff0c;各大品牌纷纷晒出优异的成绩单&#xff0c;摩根士丹利投资的智能硬件头部品牌凯迪仕也不例外。然而有爆料称&#xff0c;在自媒体平台发布霸榜各大榜单喜讯的凯迪仕智能锁&#xff0c;多个平台数据都表现出极度异常…...

    2024/5/2 5:31:39
  14. Go语言常用命令详解(二)

    文章目录 前言常用命令go bug示例参数说明 go doc示例参数说明 go env示例 go fix示例 go fmt示例 go generate示例 总结写在最后 前言 接着上一篇继续介绍Go语言的常用命令 常用命令 以下是一些常用的Go命令&#xff0c;这些命令可以帮助您在Go开发中进行编译、测试、运行和…...

    2024/5/3 1:55:15
  15. 用欧拉路径判断图同构推出reverse合法性:1116T4

    http://cplusoj.com/d/senior/p/SS231116D 假设我们要把 a a a 变成 b b b&#xff0c;我们在 a i a_i ai​ 和 a i 1 a_{i1} ai1​ 之间连边&#xff0c; b b b 同理&#xff0c;则 a a a 能变成 b b b 的充要条件是两图 A , B A,B A,B 同构。 必要性显然&#xff0…...

    2024/5/2 9:47:28
  16. 【NGINX--1】基础知识

    1、在 Debian/Ubuntu 上安装 NGINX 在 Debian 或 Ubuntu 机器上安装 NGINX 开源版。 更新已配置源的软件包信息&#xff0c;并安装一些有助于配置官方 NGINX 软件包仓库的软件包&#xff1a; apt-get update apt install -y curl gnupg2 ca-certificates lsb-release debian-…...

    2024/5/2 9:47:27
  17. Hive默认分割符、存储格式与数据压缩

    目录 1、Hive默认分割符2、Hive存储格式3、Hive数据压缩 1、Hive默认分割符 Hive创建表时指定的行受限&#xff08;ROW FORMAT&#xff09;配置标准HQL为&#xff1a; ... ROW FORMAT DELIMITED FIELDS TERMINATED BY \u0001 COLLECTION ITEMS TERMINATED BY , MAP KEYS TERMI…...

    2024/5/3 1:55:09
  18. 【论文阅读】MAG:一种用于航天器遥测数据中有效异常检测的新方法

    文章目录 摘要1 引言2 问题描述3 拟议框架4 所提出方法的细节A.数据预处理B.变量相关分析C.MAG模型D.异常分数 5 实验A.数据集和性能指标B.实验设置与平台C.结果和比较 6 结论 摘要 异常检测是保证航天器稳定性的关键。在航天器运行过程中&#xff0c;传感器和控制器产生大量周…...

    2024/5/2 8:37:00
  19. --max-old-space-size=8192报错

    vue项目运行时&#xff0c;如果经常运行慢&#xff0c;崩溃停止服务&#xff0c;报如下错误 FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory 因为在 Node 中&#xff0c;通过JavaScript使用内存时只能使用部分内存&#xff08;64位系统&…...

    2024/5/2 9:47:26
  20. 基于深度学习的恶意软件检测

    恶意软件是指恶意软件犯罪者用来感染个人计算机或整个组织的网络的软件。 它利用目标系统漏洞&#xff0c;例如可以被劫持的合法软件&#xff08;例如浏览器或 Web 应用程序插件&#xff09;中的错误。 恶意软件渗透可能会造成灾难性的后果&#xff0c;包括数据被盗、勒索或网…...

    2024/5/2 9:47:25
  21. JS原型对象prototype

    让我简单的为大家介绍一下原型对象prototype吧&#xff01; 使用原型实现方法共享 1.构造函数通过原型分配的函数是所有对象所 共享的。 2.JavaScript 规定&#xff0c;每一个构造函数都有一个 prototype 属性&#xff0c;指向另一个对象&#xff0c;所以我们也称为原型对象…...

    2024/5/2 23:47:16
  22. C++中只能有一个实例的单例类

    C中只能有一个实例的单例类 前面讨论的 President 类很不错&#xff0c;但存在一个缺陷&#xff1a;无法禁止通过实例化多个对象来创建多名总统&#xff1a; President One, Two, Three; 由于复制构造函数是私有的&#xff0c;其中每个对象都是不可复制的&#xff0c;但您的目…...

    2024/5/2 18:46:52
  23. python django 小程序图书借阅源码

    开发工具&#xff1a; PyCharm&#xff0c;mysql5.7&#xff0c;微信开发者工具 技术说明&#xff1a; python django html 小程序 功能介绍&#xff1a; 用户端&#xff1a; 登录注册&#xff08;含授权登录&#xff09; 首页显示搜索图书&#xff0c;轮播图&#xff0…...

    2024/5/2 7:30:11
  24. 电子学会C/C++编程等级考试2022年03月(一级)真题解析

    C/C++等级考试(1~8级)全部真题・点这里 第1题:双精度浮点数的输入输出 输入一个双精度浮点数,保留8位小数,输出这个浮点数。 时间限制:1000 内存限制:65536输入 只有一行,一个双精度浮点数。输出 一行,保留8位小数的浮点数。样例输入 3.1415926535798932样例输出 3.1…...

    2024/5/3 1:54:59
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57