本文描述的虚拟机内存管理优化方案,是从应用侧视角对 Android 虚拟机内存管理进行改造,优化了虚拟机对 LargeObjectSpace 的内设计思想存管理策略,间接增加其它内存空间使用上限。改造后的方案,32 位运行环境安全教育平台登录系统 LargeObjectSpace 的内存使用上限可达到 2G 甚至更多(64 位环境使用上限理论上会趋于无限大)。通过本方案可以最大程度上从系统侧解决诸多应用都会遇到的内存瓶颈和 OOM 问题,一键接入,安全可靠。
1.背景
Java OOM对于 Androi产品批号是生产日期吗d 开发者来说并不陌生,随着源码网站应用愈发复杂,部分业务在设计之初为了更好的产品体验源码是什么意思,往往会考虑用空间换时间,长此以往,安全教育平台登录入口有限的内存资源将会不堪重负,尤其是在一些重大活动期间,内存挑战会更加严峻,稍有不慎就会暴雷。
为了应对这种情况,开接口的作用发同学往往会从应用层面进行优化,减少缓存,但随着产品持程序设计思想续迭代,内存问题始终如达摩克利斯之剑,让应用处于崩溃的边缘。好在 Android 系统维护人员也意识到了这种问题,从 Android O 系统开始,对 Java 内存管理策略进行了调整,重点包括实例化 Bitmap 对象时,Bitmap 源数据的内存不再通过虚拟机申请,而是直接在 Native 层申请和管理,因此这部分内存接口测试不会纳入虚拟机 Heap 内存统计,以此来减少 LargeSpace 的占用,进而间接增加了安全教育平台学生账号登录入口其他内存空间的实际使用范围(此消彼长的关系),如下示意图:
通过调整 Bitmap 的内存管理策略以减少虚拟机整体内存使用,的确带来了立竿见影的效果。以字节公司内部诸多 App 为例,Android O 之后的移动设备,Java OOM 远远源码之家低于早期的系统版本。
2.思考与破局
对于上述 Android 内存管理策略优化,可以看到其实只有 Android N 以上版本受益,但是市面上仍有大量的低版本设备需要关注,为了带给用户更好的体验,我们开始思考,既然在 Android O 系统上可以通过调整 Bitmap 内存管理策略,以降低 Java 内存触顶压力,那么针对 Androi接口d 低版本是不是也可以考虑通过同样的方式去转移内存统计策略呢?
经过一番探索,最终找到了我们想要的答案:在应用侧,我们实现了对虚拟机内存管理策略的改造,将 LOS(Large Object Space)的整个内存使用,从虚拟机的内存统计之中进行移除,以保产品设计专业障其它内存 Space 可以更大范围地申请内存。
3.背景知识介绍
在正式介绍该方案之前,有必要先来简单了解一下 Android 虚拟机的内源码时代培训怎么样存空间管理、Ja安全教育平台学生账号登录入口va 大对象管理以及内存申请流程,以便于我们更加清接口是什么晰地理解该方案的设计思想。
3.1安全教育平台登录系统 内存空间分类
众所周知,系统在创建 Zygote 过程中会初始化虚拟机配置,其中一个便是设置 Heap 内存安全生产法。默认 HeapMax 是 256M、512M,后续应用进程通过 Zygote 进程孵化时,都会继承该配置且无法修改。但对于虚拟机来说,为了更好地管理内存并提升分配和回收性能接口的作用,并没有将所有 Java 对象全部放在一块空设计思想是什么意思间进行管理,而是按照不同的场景属性划分成若干个内存空间,这些内存空间将会系统设计思想共享虚拟机 512M 最大内存,因此它们之间是一个此消彼长的源码是什么意思关系,如下图:
同时虚拟机在 GC 过程中,可以将部分 Ob源码网站ject 对象进行移动以降低内存碎片,因此根据内存对象是否支持移动分为可移动对象、不可移动对象;按照连续性分为连续性接口类型空间(ContinuousMemMapAllocSpace)和非连续空间(DiscontinuousSpace);最终每个子类的 Space 都继承至 Space 和 Continuous接口卡Space/DisContinuousSpace,从上而下的产品设计专业继承关系,如下图:
这些内接口自动化存空间的实例化对象存储在虚拟机 Heap 对源码之家象中,申请内存时根据内存属性选择不同的内存空间进行分配和管理。
针对此文,我们重点关注的是大内存管理,以 LargeObjectMapSpace 为例,从上图可以看到它继承至非连续内存空间,对于非连续源码时代培训怎么样内存的管理要简单得多,简单总结如下:虚拟机默认把大于 3 个物理页(12安全教育平台登录入口K)的原子性对象或 String 类型的对象通过该空间进行管理,该空间所有的对象都存储在一个 Map 容器中,每次 GC设计思想 时遍历这些对象是否被引用,如果没有被引用则直接释放即可。由于这些大对象之间是离散的,因此不会造成内存碎接口是什么片问题,在 GC 时也就无需进行拷贝压缩以释放连续空间。下面我们再安全简单介绍一下 LargeObjectSpace 的角色和工作方式。
3.2 大对象内存管理
Java 大对象的内存管理比较简单,主要集中在 LargeObjectSpace 模块,主要负责 Java 大对象的内存申请和释放。
3.2.1 内存申请
结合源码,接下来简单介绍一下 Java 大对象申请流程,整理流程图如下。在此安全教育平台登录系统过程中,重点关注 Heap 已申请内存大小的更新过程和内存不足时抛出 OOM 的过程。
在上图我们可以看到,在内存实际申请过程,会首先检测当前对象是否满足大对象,具体条件是:申请对象类型设计思想是什么意思必须是原子类型或者 String 类型,并且要大于 3 个物理页。
inlineboolHeap::ShouldAllocLargeObject(ObjPtr<mirror::Class>c,size_tbyte_count)const{
returnbyte_count>=large_object_threshold_&&(c->IsPrimitiveArray()||c->IsStringClass());
}
如果满足以上条件,则会执行大对象申请流程,从 LargeObjectMapSpace 进行申请。但是在正式申请之前,会再次判断是否内存触顶,计算规则是将 Heap 中已经申请的内存和将要申请的内存进行相加,判断是否超过虚拟机的内存上限(growth_limit_),如果没有超过则说明不会触顶,然后就会直接从 LargeObjectMapSpace 申请一块内存;如果大于 growth_limit_,则说明可能会触顶,此时要先进行 GC,争取释放一些内存,如果多轮 GC 之后仍然满足不了,则抛出 OOM。
在通过以上检测之后,将会通过LargeObjectMapSpace::Alloc 实例化一个 Object 对象,如下图:
结合上图,可以看到 LargeObjectMapSpace 在内存申请过程中如要完成以下工作:
- 根据申请的内存大小,利用 me安全教育平台登录系统m_map 映射与之对应的一块内存;
- 将映射的内存转换为 mirror::Object 对象;
- 将该 Object 对象与 mem_ma源码网站p 实例进行关联,并存储到 large_objects 集合;
- 更新 largeObjectMapSpace 当前内存占用和对象数量,以及累计占用大小和对象数量;
3.2.2 内存释放
内存释放逻辑:根据传入的对象,先检查是否在 large_设计思想是什么意思objects _ 集合中,如果不存在则抛教学设计思想出异常;否则同步更新(释放)当前内存安全教育平台状态,并从该集合移源码时代培训怎么样除该对象。
在介绍完虚拟机内存空间管理以及 Large Object Space 内存管理方式的相设计思想是什么意思关背景知识后,接下接口类型来我们回归到正题,看看我们针对虚拟机是如何改造 Large Object Space 的内存管理策略的。
4. mSponge 实现原理
4.1 方案简介
为了便于更好地理解,我们将整个方案分为 2 个部分进行介接口crc错误计数绍。
一期方案:主要介绍在 Java 大对接口类型象通过 LargeObjectSpace 的内存申请和释放过程中,如何在内存申请和释放过程对其进行改造,以脱离虚拟机对这些对象的内存管理,最后实现 LargeObjectSpace 占用的内存完全脱离虚拟机内存统计。
二期方案:针对一期方案需要在应用运行过程中提前开启,但是线上 99%以上运行过程中可能不会发生 OOM,因此一期方案对系统的侵入有点高。为了优化这个现象,二期方案主要通过监听应用是否发生 OOM,如监测到 OOM 则拦截并同开启一期方案“释放更多可用软件设计思想内存”,然后安全重试内存申请,以挽救本次教学设计思想 OOM;如果没有发生 OOM,则说源码网站明内存状态良好,该方案就不需要开启。显然,这种智能式的开启方安全教育式和最大化的内存保障效果将是更加极致的解决方案。
4.2产品策略 命名由来
在运行过程中,该方案会随着 LargeObjectSpac接口和抽象类的区别e 的使用情况动态“吸收”和“释放”虚拟机 Heap 统计内存——“吸收”不希望被产品质量法虚拟机统计的 LargeObjectSpace 的内存,“释放”已经通过 GC 回收的 Large Object 内存。整个运行过程犹如海绵吸水,故将该方案命名为:Memory Sponge,寓意:内存海绵,简称mSponge。
4.接口测试3 mSponge 一期
从上面的大内存申请流程图中可以看到,如果当前内存申请满足 Java 大对象的条件(大于 12K),并在内存申请过程检测是否内存触顶时,“一直”返回 False,则可以通过 LargeObjectMapSpace 直接申请并返回对象实例,则可以绕过这里的内存触顶 OOM 问题。
同时,我们知道LargeObjectM源码apSpace 内部管理的对象是离散的,不支持虚拟机 GC 过程中连续内存空间的拷贝压缩的特性,因此即使是该空间内存占用过多,导致总内存超过了上限(512M?),但是其它连续内存 Space 的内存阈值仍然保持正常范围,因此不会影响到其他内存空间 GC 同构拷贝压缩能力,也就不会破坏虚拟接口的作用机的内存管理。
4.3.1 方案思路
那么如何才能在大对象内存触顶检测过程中绕开现有的检测机制呢?通过调研发现判断内存触顶的关键条件在于虚拟机中管理当前已申请内存 Heap::num_bytes_allocated_对象,即每次内存安全申请成功和 G安全教育C 释放接口crc错误计数时,都会同步更新该值:
inlinemirror::Object*Heap::AllocObjectWithAllocator(Thread*self,
ObjPtr<mirror::Class>klass,size*tbyte_count,AllocatorTypeallocator,constPreFenceVisitor&pre_fence_visitor){
......
//实际申请内存过程
......
if(bytes_tl_bulk_allocated>0){
size_tnum_bytes_allocated_before=
//成功申请之后,需要同步更新虚拟机整体Heap内存使用
num_bytes_allocated*.fetch_add(bytes_tl_bulk_allocated,std::memory_order_relaxed);
......
}
}
GC 过程中源码,当每个 Space 释放一定对象和内存之后,会进一步同步到虚拟机的 H安全教育平台学生账号登录入口eap 对象,同步更新虚拟机整体内存使用,接口如下:
voidHeap::RecordFree(uint64_tfreed_objects,int64_tfreed_bytes){
......
//Note:Thisrelieson2scomplementforhandlingnegativefreed_bytes.
//释放之后,需要同步更新虚拟机整体Heap内存使用
num_bytes_allocated_.fetch_sub(static_cast<ssize_t>(freed_bytes),std::memory_order_relaxed);
......
}
通过上面这个接口我们可以看到,每个 Space 在内存回收后都会更新虚拟安全生产法机更新整体内存使用情况,那么我们是不是可以在合适的时机人为主动调用该接口,减去 LargeObjectMapSpace 管理的内存值,那么 Heap::num_bytes_allocated_统计的就全部是其他内存 Space 的内存使用了;换而言之通过 LargeObjectMapSpace 申请的内存将会“脱离虚拟机”Heap::num_b接口卡ytes_allocated_源码编辑器手机版下载的统计,纳入 Nati接口ve 层的内存管理。但是这些对象的引用和内存回收机制仍然由虚拟机管理,因此并不会存在内存泄漏的隐患。
4.3.2 流程示意
L接口crc错误计数argeObjectMapSpace申请的内接口crc错误计数存,直接通过 Map 映射到虚拟内接口自动化存,因此对于产品生命周期 32 位环境应用空间可映射内存在 3G 左右,但虚拟机本身会抢先占用 1G+的地址空间用于管理安全教育平台 Java 内存,因此应用侧实际使用范围在 2G 左右安全教育平台登录系统,极端情况下调整后的虚拟机内存理论范围将在 512M~2源码编程器.5G,至于下限为何是源码网站 512M?源码之家理论上如果发生 O源码编辑器手机版下载OM 时虚拟机没有任何大对象,这种情况下,安全教育则虚拟机可用源码是什么意思内存范围将保持不变,因为我们源码时代培训怎么样改变的 Java 大对象的内存可用空间;示意图如下:
4.系统设计思想3.源码是什么意思3 关键实现
上面介绍了该方案的背景知识和实现思路源码之家,接下来就要从技术层面安全教育平台考虑如何去实现了。如果产品设计专业在系统层面,直接从源码层面定制,相关改动会轻松很多,但是对应用侧来说,要想兼容不同 Android 版本,只源码是什么意思有一条路可走——通过 InlineHook 代理相关接口,在执行过程中魔改相关参数以达到目的。在解决完接口代理问题之后,接下来还有下面几件事情要解决:
- 虚拟机并没有对外暴露获取 LargeObjectMapSpace 内存的接口,接口文档如何才能实时获取当前 Space接口测试 已申请的内存大小?
- 如何在合适的时机同步 Heap::num_b安全期计算器ytes_allocated_内存统计,以便于让 LargeObjectMapSpace 的内存”脱离”虚拟机的统计产品?
- 如何”跳过”虚拟机在内接口测试存释放过程对内存大小一致性校验的问题?
4.3.接口是什么3.1 获取 LargeObjectMapSpace 当前内存
针对第一个问题,尽管 L安全教育平台登录argeObjectSpace 中提供了获取当前内存大小的接口(LargeObjectSpace::GetBytesAllocated),但是这个接口并没有对外暴露,因此需要通过解析 Libart.so安全期计算器 中的”GetByt安全期计算器esAllocated“符号,以 A产品质量法ndroid Q 为例,该函数签名符号为: _ZN3art2gc5space16LargeObjectSpace17GetBytesAllocatedEv;并在运行过程中动态获取该符号在内存中产品的地址。
由于 GetBytesAllocated 是非静态函数,因此产品设计在实际调用该接口时,需要知道当前产品批号是生产日期吗对象的实例化对象,然后通过实例化对象调用该接口即可,在这里,我们通过 inlineHook 代理”LargeOb源码资本jectMapS源码编辑器手机版下载pace::Alloc”获取 L源码网站argeObjectMapSpace 的实例,LargeObjectMapSpace::Alloc 接口部分源码如下:
mirror::Object*LargeObjectMapSpace::Alloc(Thread*self,size_tnum_bytes,size_t*bytes_allocated,size_t*usable_size,size_t*bytes_tl_bulk_allocated){
std::stringerror_msg;
MemMapmem_map=MemMap::MapAnonymous("largeobjectspaceallocation",
num_bytes,
PROT_READ|PROT_WRITE,
/*low_4gb=*/true,
&error_msg);
......
//申请成功后将当前内存占用+allocation_size
num_bytes_allocated_+=allocation_size;
total_bytes_allocated_+=allocation_size;
++num_objects_allocated_;//申请成功后将当前内存数量+1
++total_objects_allocated_;
returnobj;
}
在获取 LargeObjectMapSpace 的实例化对象之后,再通过该对源码编辑器手机版下载象直接调用 GetByt产品批号是生产日期吗esAllocated即可实时获取当前接口英文 LargeObjectMapSpace 的内存大小。
4.3.3.2″移除”LargeObjectSpace 内存安全教育平台
当我们可以实时获取 LargeObjectSpace 的内存使用之后,接下来便是如何从虚拟机 Heap产品设计 中“移除”LargeObjectSpace 实际占用的内存了,通过调研发现可以通过解析”Heap::RecordFree“函数符号,并调用Heap::R产品设计ecordF安全生产法ree 的函数接口,增加或减少 Heap 中我们想要更新的内存大小。
voidHeap::RecordFree(uint64_tfreed_objects,int64_tfreed_bytes){
......
//Note:Thisrelieson2scomplementforhandlingnegativefreed_bytes.
num_bytes_allocated_.fetch_sub(static_cast<ssize_t>(freed_bytes),std::memory_order_relaxed);
......
}
当上述条件满足我们可以灵活更新虚拟机 Heap 内存之后,接下来要处理的就是选择一个合适的时机直接“移除”LargeObjectSpace 的内存,并且需要更新记录当前 Heap“移除”的内存大小,经过调研并考虑到及时性和精准性,最终选择了在 LargeObjectSpace 的内存申请和回收过程,对虚教学设计思想拟机 Heap 内产品设计存进安全教育平台官方网站行动强制更新,以移除虚拟机对 LargeO接口的作用bjectSpace 的内存统计。
在 Large Object 申请过程,如果内存申请成功,则在该 Object 实例化对象返回之安全教育平台官方网站前,先强制从虚拟机内存统计中减去该部分内存,接下来虚拟机内部会在返回实例化对象之后,并统计本次新增内存,在这里我们通过源码网站先减后加的方式,维持了整个内存水位不变,从而间接地实现了虚拟机“忽略”了本次内存开销。
如果后续 GC 过程中释放了 LargeObjectSpace 中的部分或者全部对象,正常接口的作用情况下释放的内产品策略存会同步同步到 Heap,以便于更新整体使用内存及可用内存,但是从上面的分析中我们知道,其实 LargeO安全教育平台学生账号登录入口bjectSpace程序设计思想 的内存已经不在 Heap 统计之中了,如果从 Heap 中减去释放的这些内存,那么将会导致 Heap 统计的内存偏少,因此需要主动将该部分释放的内存”补偿”回来,避免统计产品经理错乱。
通过上述步骤实现了产品批号是生产日期吗在内存回收过源码编程器下载程中对大对象内存管理的改造,改造之后 Heap 统计的内存将不再包含 LargeObjectSpace 管理产品经理的内存,从而间接地扩大了其他内存 Space 使用上安全期计算器限;对于 LargeObject产品批号是生产日期吗Space 来说,虚拟机统计到的该内存 Space 一直为 0,但是 LargeObjectSpace 内部并没有内存限制,异常该 Space 的内存使用上限将会显著提升,针对 Android O 以下系统来说,这部分内存 Space 不仅包含 Bitmap,还包含其他大对象。
4.3.3.3 内存校验
在适配过程中,发现 Android L 版本之后,虚拟机会在 GC 过程中对释放内存和使用内存进行一次校验。如果发现当前使用内存加上释放内存小于 G源码是什么意思C 之前的内存,源码编辑器则会抛出“断言”异常,相关源码如下:
voidHeap::GrowForUtilization(collector::GarbageCollector*collector_ran,
uint64_tbytes_allocated_before_gc){
//GC结束后,再次获取当前虚拟机内存大小
constuint64_tbytes_allocated=GetBytesAllocated();
......
if(!ignore_max_footprint_){
constuint64_tfreed_bytes=current_gc_iteration_.GetFreedBytes()+
current_gc_iteration_.GetFreedLargeObjectBytes()+
current_gc_iteration_.GetFreedRevokeBytes();
//GC之后虚拟机已使用内存加上本次GC释放内存理论上要大于等于GC之前虚拟机使用的内存,如果不满足,则抛出Fatel异常!!!
CHECK_GE(bytes_allocated+freed_bytes,bytes_allocated_before_gc);
}
......
}
因为我安全教育平台登录系统们在内存 GC 过程中,动态调整了 Heap 当前使用内存大小,这可能会导致 gc 结束源码编辑器后再次获取的 Heap 当前使用内存小于实际值,为了不影响校验逻辑,需要代理 Heap::GrowFor安全Utilization 接口,强制将bytes_安全教育平台登录入口allocated_before_gc 参数设置设计思想怎么写模板为 0,以保证校产品设计验恒成立(针对该处调整从后续逻辑和实际测试来看,对后续内存 GC 并无明显影响) 。接口crc错误计数
4.3设计思想.4 小结
至此,通过上述思路和技术方案完成了 Android 虚拟机内存统计策略的改造,该方案不仅间接源码网站提升了虚拟机其它内存空间运行时的使用上限,也将 LargeObjectSpace 的内存使用上产品介绍限完全脱离源码是什么意思了虚拟机的设计思想是什么意思限制,完全产品等同于 Native 内存属性进行管理。因此该方案相比 An接口droid 系统 Bitmap 内存管理改造更加彻底,给应用的内存环境带来了极大的改善。
4.4 mSponge 方案二期
在上文,对内存统计策略源码时代培训怎么样改造之后可以很大程度释放 LargeObjectSpace 内存空间以优化 Java OOM 问题,但是进一步思考之后,发现一期方案并不是最优解,因为应用运行过程中很大概率不会发生 OOM,如果能监听到 OOM 时,再启动优化方案,同时再救活本次 OOM,那么这种智能化的按需开启将是极致化的解决方案。
4.4.1 方案思路
针对上述思考,基于 mSponge 方案一期的设计产品密钥,决定采用“OOM 探测+按需开启”的策略来完成对内存的按需扩展。即:对内存申请过程进行定向监控,当监源码网站听到内存不足即将抛出 OOM 异常时,进源码编程器下载行拦截,设计思想是什么意思并激活 mSponge 方案一期内存优化方案(从 Heap 内存统计中移除当前 LargeObjectSpace 使用内存);然后再触发一次内存申请,以保证安全教育平台学生账号登录入口内存成功申请。按照上述思路,整理方案优化前后对比示意图:
4.4.接口的作用2 流程示意
基于上面的思路,我们需要在虚拟安全教育平台机内部监听源码编辑器手机版下载并拦截 OOM,当监听到第一次 OOM 时主动将 LargeObjec产品生命周期tSpace 的内存从 Heap 统接口自动化计中移除,以增加空闲内存,同时再开启 mSponge 一期优化策略,以保证后续 LargeObjectSpace 的内存变化不会影响 Heap 内存统计;按照这种思路,整体二期方案示意图如下:安全
4.4.3 关键实现
二期技术实现主要涉及下面几个流程:监听并判断是否需要拦截 OOM 异接口和抽象类的区别常;程序设计思想监听内存分配结果;重试内存申请。具体如下:
- 监听 OOM 异常:代理 Hea教学设计思想p::ThrowOutOfMemoryError,监听内存分配失败时抛出 OOM 的安全教育平台登录过程,并判断是否需要拦截,如果可拦截。
- 监安全期计算器听内存分配结果:代理 Heap::AllocateInternalWit产品设计专业hGc ,监听本次内存申请过程中,是否发生了 OOM 并被拦截,如果发生 OOM 并产品被拦截,则再次触发内存申请,以保证内存申请成功接口类型。
- 重试内存申请:通过 AllocateInternalWithGc 再次触发一次内存申请,并在此之前禁止拦截本次内存申请过程中设计思想怎么写模板可能抛出的 OOM,如果成功申请,则返回该对象。
4.4.3.1 监听 ThrowOutOfMemoryError
通过 inlineHook 代理”Heap::ThrowOutOfMemoryError”并监听该接口,如果该接口被调用源码编辑器手机版下载则说明,当前内存不足或者没有连续内存,无法满足本次源码资本内存需求;并根据调用 AllocateInternalWithG源码c 代理接口设置的标识”产品经理sAllowsSkipThrowOut设计思想OfMemoryError“,判断是否拦截本次 OOM 异常;实现如下:
voidThrowOutOfMemoryErrorProxy(void*heap,void*self,size_tbyte_count,AllocatorTypeallocator_type){
if(isAllowWork()){
sFindThrowOutOfMemoryError=true;
if(sAllowsSkipThrowOutOfMemoryError
&&!sForceAllocateInternalWithGc){
//拦截并跳过本次OutOfMemory,并置标记位
sSkipThrowOutOfMemoryError=true;
//TODO:将LargeObjectSpace内存从Heap中移除
return;
}
sSkipThrowOutOfMemoryError=false;
//如果不允许拦截,则直接调用原函数,抛出OOM异常
ThrowOutOfMemoryErrorOrigin(heap,self,byte_count,allocator_type);
}else{
ThrowOutOfMemoryErrorOrigin(heap,self,byte_count,allocator_type);
}
}
4.4.3.2 代理 A产品密钥l接口文档locateInt源码编辑器手机版下载ernalWithGc
通过 inlineH产品ook 代理”Heap::AllocateInternalWith接口Gc”代理并监听该接口,因为在该接口执行过程中会触发一次或多次 GC,如果依然满足不了本次内存申请,则会抛出 O源码时代培训怎么样OM 并返回 NULL;因此可以源码网站通过代理该接口可源码时代培训怎么样以知道本次内存申请是否成功,以及本次申请过程中是否抛出 OOM 异常;如果返回对象为 NUL产品设计专业L,并拦截了 OOM 异常,则设置禁止拦截 OOM 标记之后,调用 Heap::AllocateInternalWithGc 原接口再次进行内存申请,以保证安全教育平台学生账号登录入口成功申请内存。
原则上通过 mSpnge 方案将 LargeObject源码之家Space 的内存从 Heap 移除之后,理论系统设计思想上虚拟机可产品经理用内存会增加很多,基本能保证本次内存成功申请(极端情况仍会出现内存不足,正常抛出 OOM 即可)。
void*AllocateInternalWithGcProxy(void*heap,void*thread,
AllocatorTypeallocator,
boolinstrumented,
size_talloc_size,
size_t*bytes_allocated,
size_t*usable_size,
size_t*bytes_tl_bulk_allocated,
void*klass){
if(isAllowWork()){
//设置标记位,允许拦截本次内存申请过程的OOM
sAllocateInternalWithGc=true;
sForceAllocateInternalWithGc=false;
//调用原始接口,并判断返回object是否未NULL
void*object=AllocateInternalWithGcOrigin(heap,thread,allocator,instrumented,alloc_size,bytes_allocated,usable_size,bytes_tl_bulk_allocated,klass);
sAllocateInternalWithGc=false;
//如果返回object为NULl,并且在此过程中抛出了OOM异常,则说明内存不足导致申请失败,则开启虚拟机内存统计策略优化方案,释放LargeObjectSpace内存
if(object==NULL&&sAllowsSkipThrowOutOfMemoryError&&sSkipThrowOutOfMemoryError){
//设置标记位,不允许拦截本次内存申请过程的OOM
sForceAllocateInternalWithGc=true;
//再次调用内存申请,争取成功申请内存
object=AllocateInternalWithGcOrigin(heap,thread,allocator,instrumented,alloc_size,bytes_allocated,usable_size,bytes_tl_bulk_allocated,klass);
sForceAllocateInternalWithGc=false;
}
returnobject;
}else{
returnAllocateInternalWithGcOrigin(heap,thread,allocator,instrumented,alloc_size,
bytes_allocated,usable_size,
bytes_tl_bulk_allocated,klass);
}
}
4.4.4 小结
至此,通过上述思路和技术方案完成了应用内存申请过程中的 OOM 监测,安全并在虚拟机内存抛出 OOM 的过程对 Heap 的内存管理进行了改造,移除了 LargeObjectSp安全教育平台登录入口ace 的内安全教育平台学生账号登录入口存占用,间接增加了虚拟机可用内存之后,再次触发内存申请,以拯救本次 OOM;通过这种按需开启的方式,体现了以最小化的侵入成本换来最大化的内存保障。
5.方案收益
以今日头条 32 位测试环境为例,通过该方案对虚拟机大对象内存扩展了 500M(实际使用可根据产品自身特点设置扩展内存大小),通过测试用例连续占用 500M 内存后,虚拟机内存分布如下图:
从上图可以清晰看到虚拟机其它内存空间(main space)仍然是 1G 大小,但是large space 内存大小接近 600M,内存可用范围得到明显增加。
5.1 统一 Large Object 管理策略
通过该优化方案,源码实现了在应用侧对 Android 各版本虚拟机内存管理策略的统源码时代培训怎么样一,弥补了 Android 系统优化向下兼容性不足的缺陷,很大程度降低了产品设计和 RD源码时代培训怎么样 开发过程,需要对低版本内存管理差异性进行降级或产品生命周期兼容的成本。
系统版本 | 虚拟机最大可用内存 | LargeObjectSpace 最大可用内存 | 说明 |
---|---|---|---|
Android O 以下 | 512M | 512M | 1.所有内存空间共享虚拟机 512M 内存安全教育平台官方网站 2.Bitmap 源数据纳入 Java 内存统计 3.LargeObjectSpace 与其它内存空间共享 |
Android O 以上 | 512M | 512M | 1.所有内存空间共享虚拟机 512M 内存 2.Bitmap 源数据纳入 Java 内存统计 3.LargeObjectSpace 与其产品经理它内存空间共享 |
mSpo产品nge 改造方案 | 512M | 32 位:2G/3G | 1.除 LargeObjectSpace 之外,其它内存空间共享 5接口是什么12M 内存 2.Larg接口eObjectSpac产品e 整体内存不再纳入 Java 内存统计 |
5.2 OOM 收益
统计近半年头条线上 OOM Case(集中安全发生在 Android O 以下版本,因为低版本 Bitmap 内存纳入虚拟机管理安全期计算器和安全教育平台登录入口统计,更加容易导致内存触顶),都发生在部分图片缓存过高,或者各种节日运营导致 Bitm接口和抽象类的区别ap 缓存不合理;由于该方案将虚拟机大内存的统计进行了优化,相当于“扩展”了虚拟机可用内存,因此对于上述场景导致的 Java OOM 问题,起到很好的容错能力,挽救 90%以上的 OOM 问题。
6.总结
通过上文,我们以 32 位运行环境为例,介绍了Android 虚拟机内存管理策略的改造思路,改造之后的内存管理策略,统一了 Android 系统碎片化的内存管理差异,进一步优化应用的运行设计思想环境,显然更加符合应用侧对 Java 内存的使用诉求,更好地应对和保障了应用接口类型运行时的稳定性,带给用户更好体验。
7.后续
在移动互联网快速迭代的背景下,各类应用也在快速迭代,如何更好地保障线上质量,将是一种长期需要应对和探索的方向,除了在常规视角进行优化之外,如何进行更深层次的源码时代系统探索,也是安全教育平台登录系统我们日常工作的主要方向,后续我们将会分享更多关安全期计算器于系统层面的相源码编程器下载关实践。
加入我们安全教育平台官方网站
我们是产品运营字节跳动Android 平台架构团队,以服务今日头条为主,面向 GIP,同时服务公司其他产品,在产品性能稳定性等用户体验、研发设计思想怎么写流程、架构方向上持续优化和探索,满足产品快速迭代的同时,保持较高的用接口的作用户体验。
如果你对技术充满热情,想要迎接更大的挑战和舞台,欢迎加入我们。北京、深圳均有岗位,感兴趣发送邮箱:tech@bytedan设计思想怎么写模板ce.com接口文档,邮件标题:姓名安全教育平台学生账号登录入口 – GIP – Android 平产品批号是生产日期吗台架构。