抖音一直显示此应用正在加速优化中,请稍后重试。打不开怎么办?

编辑导语:在短视频时代,短视频平台巨头抖音的用户数以亿计,但是抖音重运营、轻产品的运营思路导致很多功能使用起来十分不方便,本篇文章作者列举了假设抖音新增 10 大功能,你最喜欢哪个呢?一起来看一下。

2016 年秋,字节跳动上线了一款叫 A.me 的产品。

三个月后," 晃音 "、" 抖咖 "、" 抖音 " 等名称在应用商店投放进行 AB 测试分析数据后,A.me 改名 " 抖音 ",当时在字节跳动内部直到最初是边缘产品。

抖音虽在产品上抄袭 Musical.ly,但内容生态建设标新立异,这也是抖音崛起原因之一。建立诸如:武术、健身、旅行、赛车、冲浪、红酒、绘画、音乐、舞蹈、美妆、烹饪等等数百个垂直标签。

抖音取胜最关键在于,是 " 字节在做它 ",有中台和综合能力支撑(高效的推荐算法做人和信息匹配、高效的用户增长、高效的商业化)。

截至 2020 年 8 月,包含抖音火山版在内,抖音日活超过了 6 亿。与之对应的是,快手 2018 年初的日活约 1 亿;2019 年 5 月突破 2 亿;2020 年初为 3 亿。

截止 2022 年 3 月,抖音 + 抖音极速版 + 抖音火山版已超过 6.6 亿用户,日均播放视频超百亿、年播放视频数万亿次。

抖音重运营,轻产品,有些功能使用起来十分不便,如果抖音增加这 10 个功能,你会最喜欢哪个?

一、自动播放下一个功能:播完上一个视频自动播放下一个视频

在关闭算法推荐时,提供自动播放功能。

用户需求强烈且实现成本很低,为什么抖音一直不做呢?

今日头条、抖音之所以会成为国民 APP,都是因为他的算法能够精准判断出用户的兴趣偏好,并依据判断出来的兴趣偏好来给用户推送同一兴趣领域的视频。YouTube 曾测试过个性化推荐的点击率是热门视频点击率的 2 倍。如果抖音变成自动播放,完播率数据会失真,将会损害性去判断的精准度。

抖音算法对于用户所刷视频的兴趣判断,主要来自于四部分数据:

用户基础属性:性别、年龄、地域和位置、终端环境(网络环境、运营商画像、设备型号);

用户的点赞、评论、收藏、转发等行为数据;

是用户在该视频上的停留时间;

算法是一个递减函数,用户停留时间所占的权重较大。

用户在视频上停留的时间越短,越快划走,就说明用户对于此类视频不感兴趣,可以减少同类推荐。相反,用户在视频上停留的时间越长,看完甚至反复观看,说明用户对这类视频感兴趣,可以增加同类推荐。

在关闭算法推荐功能时,默认视频连播,并提示关闭位置。

此功能在关闭算法推荐用户达到一定体量后可能会出现,否则用户可能永远看不到。

算法取得突破后也可能会增加自动连播功能。

二、沉浸模式:屏幕非视频元素越来越多,非直播模式也提供清屏功能。

1)方案一:建议双指 / 三指点击清屏。三指点击一般不会误操作,比如 IOS13 系统在输入文字时,三指单击屏幕即可调出快捷文字菜单。ABtest 方案:可用多种手势操作测试,最终分析数据决策用哪种方案。

2)方案二:页面设计图标,点击图标清屏,只展示视频和用户名主要元素。这种方案很差,页面元素图标已经越来越多了,非核心功能页面上不应再加入图标。手势交互操作是最优的方案。

三、查看博主当前相关视频:交互优化

右滑 / 点击头像 / 点击用户名 进入个人作品页:

下方出现刚刚看过的图标:

点击一次、页面滑动、再定位到刚刚看过的视频上,此时人眼还要扫描寻找一下才能找到。现在的方案用户体验非常差、糟糕透顶!

分析:看得出抖音收集到了此类的用户吐槽,也进行了几版的优化,但是优化结果不尽如人意。

如果涉及为右滑展示缩略图,可能抖音考虑会减少博主首页的展示量,进而减少关注量、商品橱窗的转化。但是强制增加用户操作路径,来提升数据,长期来看真的利大于弊吗?如果抖音产品经理看到,可以交流一下。

→右滑,预览相关视频,上下滑动可快速浏览相关视频,商品橱窗固定展示。

1. 评论区分热门、最新

背景现状:评论区没有做最新 / 热门分区,几乎是根据点赞排行,应该是算法排行展示,想查看最新评论需要一直下滑搜寻

优化方案一:增加 评论区热门、最新的分类 tab 标签

优化方案二:右上角增加一个图标筛选项,点击展示热门 或最新评论按钮,点击按钮展示热门 / 最新评论。

评论踩:视频踩影响博主的创作积极性,而评论踩并不会。

五、增加赞之外其他的表达情绪的图标

2009 年,Facebook 上线了 " 点赞 " 功能,显著提高了用户留存量,发帖数量和质量都随之提升,约 30% 的用户每天都会多次点赞。赞自从被发明以来,被各行各业广泛采用。点赞行为本质是表达同理心,但是并非当下视频的都是令人开心的,有时候也想表达伤心和愤怒。

当前抖音月活逼近 7 亿,日均播放视频数百亿次、年播放视频数万亿次!抖音稳坐短视频老大地位,即使加入了负面情绪图标也只会走向正反馈,当然也要看数据了。当前抖音仅有的一个赞,对视频表达同理心、表达情绪是不够的,比如对下列场景做了简要分析。

长按赞弹出其他情绪图标,可点击其他图标表达态度。

快速点击图标,增加交互效果,展示酷炫特效。也可以加个连续点赞到 100 下的彩蛋!

六、视频播放模式多样化

听视频、后台播放:已经在小范围测试中了。

VR 模式:字节收购 Pico 后,有助公司整体战略,元宇宙概念战略上可探讨更多玩法。

很多视频只能竖屏看一部分,不能横屏;只有由横屏按钮的适配才可以。但是竖屏太小观感不佳,可增加只能扩展全屏功能。

提供可选择的智能全屏功能(竖屏智能横屏、竖屏智能填充屏幕)。

当前只能发布文字、图片、视频,不能发语音动态,竞品也都不能。如果增加这个功能可以增加用户的互动," 更好玩 ",或者造个语音节。

弹幕功能:为什么有了评论还需要弹幕功能呢?

对于页面观感问题和部分客群非受众用户问题,可通过提供默认关闭弹幕的方式解决。

短视频和长视频最为显著的区别就是短视频太短!那么可通过限制一定时间 x 秒内(比如 30s)的视频不支持弹幕,可通过 ABtest 决策 x 具体数值。

官方角度:短视频主要关注点赞、评论数、转发数、完播率,如果增加弹幕,抖音官方的考核指标就要变化,可能抖音内部还没有考虑好如何衡量这一指标才没有推出弹幕功能。

图片海报:使用相应图片生成可编辑海报,留下美好瞬间。

评论海报:引相应评论生成可编辑海报,留下美好文字。

抖音从 0 到 1,出生的比快手晚,却在短短 5 年时间,稳坐短视频老大的位置。作为国民级的应用,年播放视频次数达到了恐怖的万亿次!

至今抖音与快手用户重合率约 60%,而抖音用户量近 7 亿、快手仅有 5 亿多用户。

也就是抖音能抢快手的用户,反过来快手抢不走抖音的一部分用户。抖音乘着移动互联网的春风,一路披荆斩棘成为字节跳动的超级印钞机。

所以,可能抖音如何的产品形态就是最正确的抉择结果。

然而,没有任何产品可以永远稳坐钓鱼台,不知下一波风浪会有谁掀起!

一篇小文,如果抖音增加这 10 个功能,你最喜欢哪个?

本文由 @零一集 原创发布于人人都是产品经理,未经作者许可,禁止转载。

在抖音,用户可以进行短视频的内容创作,然后通过接广告来赚钱。也可以开抖音小店来卖东西赚钱。无论是哪种方式,都需要有流量。那抖音流量上不去该怎么办?

你每次发布视频,都会给你一个最基本的流量池来测试你的视频,但是因为你的视频表现不佳,所以没办法给你再多的播放量,只能说账号权重比较正常,但是内容质量肯定一般。

你可以用以下三个方式进行优化和修正,分别是养号、优化内容、投DOU+,我们一个个来讲。

第一个是养号,如果你的播放量每天都是瓶颈上不去,有可能是内容还不够垂直,抖音无法给你打上明确的标签,你仍然在测试流量里,所以要尝试调整内容,让账号输出的内容更垂直,打上精准的标签,从而提升基本播放量。

第二个是优化内容,要检查你的视频是不是不符合平台拍摄需求?拍的内容是不是过于粗糙简?这两点是非常关键的,如果没有好的内容,在抖音上是不可能推爆的,所以好好优化内容,是做抖音最重要的工作。

如果你觉得内容不错,账号质量和打标也已经完成后,播放量还是上不去,可以尝试投DOU+,起码买进来的播放量都是真实流量,价格也不贵,99元5000播放量,并且视频多了之后,可以通过数据样本找出视频的不足,这跟测款的道理一样。

总的来说,抖音流量上不去主要的原因在于前期的定位不准确,内容质量不行。所以要想改变这一现象,就要把内容做好,把自己的定位弄准确。

作为 Android 开发者,相信大家都碰到过 Java OOM 问题,导致 OOM 的原因可能是应用存在内存泄漏,也可能是因为手机的 heapsize 比较小不能满足复杂应用对内存资源的大量需求。对于 Java 内存泄漏治理,业界已经有比较成熟的方案,这里不做介绍,本文主要针对第二点尝试进行分析和优化。

举个例子:我们在监控平台查看稳定性数据,发现 heapsize=256M 的设备发生的 OOM 崩溃最多,而 heapsize=512M 的设备很少发生 OOM 崩溃。且除此之外,还有一个特点:OOM 崩溃绝大多数发生在 Android 8.0 之前的设备。

对于这种 heapsize 较小难以满足业务复杂度的情况,可能有以下几种方式来解决:

如果我们已经设置了 largeHeap,也就没有常规的提升 heapsize 的方式了;再想往前一步,可以尝试从虚拟机中突破这个限制,因为 heapsize 是虚拟机的配置,是否抛出 OOM 异常也是在虚拟机中决定的;修改虚拟机运行逻辑是有一定可能的,但是其难度和可行性与想要修改的内容相关性较大,修改方案的稳定性也需要非常深厚的功力才能保证,而如果运气不好,找不到好的切入点,甚至从理论上都无法保证其稳定性,那么达到上线的难度就更大了,本文不在这个方向深入。

2. 降低业务复杂度,裁剪应用功能

这个方案也不在我们的考虑范围之内,实际上很多应用都有推出极速版,但是功能都会有所裁剪,对于使用常规版本的用户,我们也不能推送极速版,因为使用体验会有很大变化。

3. 分析 Java Heap 里的内容都是什么,尝试发现主要矛盾进行优化,对症下药

实际上本文就是从这个方向经过调查后,找到了一个相对稳定的突破口。下面是结合 OOM 堆栈、android 版本、heapsize 维度对 OOM 整体概况的一个分析:

出现最多的堆栈就是 Bitmap 创建时内存不足从而 OOM 崩溃,那么是不是已使用的内存大多都是 Bitmap 呢 ?不能 100%确定,因为直接触发 OOM 崩溃的原因是最后一次内存分配失败,而真正的原因是 OOM 之前的内存分配;但是仍然有一定可能性,因为总是出现同一个堆栈可能并不是巧合,可以在一定程度上说明这个堆栈执行的比较频繁,而且 Bitmap 一般占用内存较大。

这里先做一个不 100%确认的初步推断:OOM 时 Java heap 中占用内存较多的对象是 Bitmap

继续对 OOM 数据做总结后发现了 OOM 的分布规律如下图:

第四象限的数据说明,即便在 heapsize 较小的情况下,在 android 8.0 之后的版本上也不容易发生 OOM,结合上面的初步推断信息“OOM 时 Java heap 中占用内存较多的对象是 Bitmap”,很容易想到,应该是 Bitmap 在 android 8.0 前后的实现变化导致了当前的 OOM 分布现象:

由于 Native heap 的内存分配上限很大,32 位应用的可用内存在 3~4G,64 位上更大,虚拟内存几乎很难耗尽,所以在前面的推测 “OOM 时 Java heap 中占用内存较多的对象是 Bitmap” 成立的情况下,应用更不容易 OOM。

至此,得到了确定的结论

根据上述结论,目标也就比较清晰了:

二、Bitmap 使用分析和方案调查

如下堆栈描述了 Bitmap 的创建:

这个信息可以作为一个切入点,在后面进行深入调查。

通过初步的分析,初步有两个思路可以先进行尝试:

这个思路看起来想要实现目标,做一下替换就可以了,但实际上没有这么简单,存在的问题如下:

  1. Bitmap 内存的申请和释放要有匹配的逻辑和合适的时机

所以这个思路基本可以断定不可行。

其中 External 方式存储 Bitmap 像素,在源码中没有看到相关使用,无法参考;Java 类型就是默认的 Bitmap 创建方式,像素内存分配的 Java 堆上;Ashmem 方式存储 Bitmap 像素的方式在源码中有使用,主要是在跨进程 Bitmap 传递时使用,对应的场景主要是 Notification 和截图场景:

但经过详细的源码分析以及实际验证,其可行性仍然很低,主要原因如下:

实际情况中,6.0 系统的 OOM 占了非常大一部分,如果这个方案可行,也可以解决一部分问题,所以不会因为这个原因阻碍对这种方案的尝试,还可以继续尝试

2 . ashmem 方式存储 Bitmap 像素,每个 Bitmap 需要对应一个 fd,应用的 Bitmap 使用数量是能够达到 1000+ 的,这样可能会导致 fd 资源使用耗尽,从而发生崩溃

这个问题基本是无解的,但如果方案可行,可以尝试只给一定数量的 Bitmap 使用 ashmem 方式申请像素内存,比如 500 个;所以方案还可以继续尝试

3 . 最终尝试后发现这种方式影响 Bitmap 正常功能(一些视频动图不能正常展示),经分析主要原因是使用 ashmem 申请的 Bitmap 无法进行 reconfigure :

方式创建的 Bitmap 没有从 Java 堆申请 mBuffer,所以一定是不支持 reconfigure 的。当然到这里之后还没有完全堵死这个方式,还可以继续尝试在 ashmem 方式申请 Bitmap 时给其一个假的 mBuffer 来绕过这个限制,但接下来要做的调查和改动势必很大,因为 ashmem 方式申请 Bitmap 本身不支持 mBuffer 的管理,新创建的 buffer 就难以找到合适的时机进行释放。

结合上述 3 个点综合判断,这个方案限制比较多,也有一定风险,所以暂时将当前的方案暂时挂起,作为备用方案。

上述的两种思路不成功其实有一定的必然性,毕竟对应代码的设计并不是为了给我们取巧做切换用的。既然没有办法这么容易实现,就深入调查清楚为 Bitmap 从 Java 堆申请内存的流程和这个内存的使用流程,再尝试从这些流程中找到切入点进行修改。

思路 3:剖析 Java 堆分配 Bitmap 内存的过程,再尝试找到方案

实际就是查找 hook 点的思路,先分析内存是如何分配的,分配出来的内存是如何使用的(主要指分配出内存后,指针或者对象的传递路径),尝试把从 Java 堆分配内存的关键点替换为使用 malloc/calloc 函数从 Native 堆上进行分配,并把分配出来的内存指针构造成原流程中使用的数据结构,并保证其能够正常运行。

上图为简化后的核心内存分配流程,框起来的部分就是为 Bitmap 从 Java heap 申请像素内存的代码。其中:

这里需要先说明一下 java byte array 的内存布局(对应代码在 ART 虚拟机中):

想要把 Bitmap 内存分配改为在 Native 层分配,就需要从分配这里入手, 所以必须要把 arrayObj 和 addr 使用梳理清晰,为后续替换和适配做好铺垫。arrayObj 和 addr 使用如下:

Bitmap 像素的内存地址,即 arrayObj 的元素地址 addr,其是作为指针类型数据来使用的。

小结:addr 指向的内存是在 java 堆上,其会在需要的时候被传递给 skia 用来处理 bitmap 像素数据。

skia 中并不会为 Bitmap 的像素数据分配内存,它把 Java heap 上 byte 数组的元素首地址转换为 void* 来使用;也就是说在当前实现中,Bitmap 像素内存不一定非得是在 Java heap 上分配,我们可以 malloc 一块内存传递给 skia 使用,并不需要再给 skia 做任何适配。

有了上面这些信息,把 android 8.0 之前的 Bitmap 像素内存改到在 Native 层分配目标就看到了希望,因为不需要在 skia 层适配,可以降低一定难度。

根据上面的分析,只需要找好 hook 的切入点,并完成 3 个关键点的替换即可,如下图:

Bitmap 的内存分配了),所以只能给个假的。

这种方式看起来好像不太稳定,但是可以通过校验来保证,比如我们在执行方案之前先尝试伪造一个 byte array 来进行验证,如下代码就是申请了 1 字节长度的 byte array,把它的长度伪造成 36,然后进行校验,校验失败则不再执行 NativeBitmap 方案。

的距离。接下来需要完成 malloc 出来的 Bitmap 内存的释放逻辑。

  1. 给 Java Bitmap 使用的小 size 的 byte array 对象,这个对象仍然按照原生逻辑释放,无需再做其他变动
  2. malloc 出来的用以存放 bitmap 像素数据的内存,在 byte array 释放时进行 free,相当于附着于原生的内存释放逻辑,从而不会影响 Bitmap 的生命周期

实现释放有两个关键点:

1 . malloc 出来的指针需要与 mBuffer 关联,这样才能在 mBuffer 释放时找到对应的内存进行释放

上的方案理论上完全可以实现,且需要的改动不大,只需要在原生 Bitmap 的创建流程和释放流程中做好修改即可。

根据上述思路 3 的方案,最终实现如下:

改造前 Bitmap 的创建和内存申请流程:

改造后 Bitmap 的创建和内存申请流程:

改造后在 Bitmap 创建过程中做了两个 hook,对应上图中两条紫色箭头指向的代码:

在 addressOf 的代理函数中根据前 4 个字节数据是否是 magic number 来判断传入进来的 array 是否是被改造的 array,如果不是则调用原函数进行返回,如果是则继续进行下述步骤;

  • 把 bitmap 指针返回,由原生逻辑在后续传递给 skia 使用;

在后面释放 Bitmap 相关内存时会使用到 byte array 中填充的这些数据。

在前面提到过申请的 fakeArray 本身占用的内存就作为 Bitmap 内存转移到 Native 层的代价,到这里及可以计算一出 Bitmap 被转移到 Native 层需要付出的内存代价是多少 ?

上图中虚线上方为原生的释放流程,虚线下方是在原生流程上新添加的释放流程。其中右侧的代码就是新的逻辑下对 Bitmap 像素数据和辅助数据释放的关键代码。释放逻辑已经在第二大节中的 [新的释放逻辑] 中说明,这里不再复述。

对象,从而回收其对应的 Native 层像素内存。

这种情况可以通过在 native 内存申请和释放时通知到虚拟机,由虚拟机来判断是否达到 GC 条件,来进行 GC 的触发。实际上 android 8.0 之后 Bitmap 内存申请和释放就是使用的这个方式。

目前该方案支持到 android 5.1.x ~ 7.x 的系统。4.x~5.0 的系统较早,实现差异较大,待后续完善。

四、线下验证和线上效果

在测试代码中尝试把一个 bitmap 缓存 5001 次:

完成加载 5001 个 Bitmap,并且应用仍能够正常使用:

在使用中我们对 NativeBitmap 方案的使用做了限制,因为 Bitmap 内存转移到 Native 层之后会占用虚拟内存,而 32 位设备的虚拟内存可用上限为 3G~4G,为了减少对虚拟内存的使用,只在 heap size 较小的机型才开启 NativeBitmap。我们在持续的优化中发现 Android 5.1.x ~ 7.1.x 版本上,已经有很多设备是 64 位的,所以当用户安装了 64 位的产品时,就可以在 heap size 较大的机型上也开启 NativeBitmap,因为此时的虚拟内存基本无法耗尽。在 64 位产品上把开启 NativeBitmap 的 heap size 限制提升到 512M 之后,Java OOM 数据在优化的基础上又降低了 72%。

有两个问题做一下说明:

答:并不是,NativeBitmap 只是把应用内存使用的大头(即 Bitmap 的像素占用的内存)转移到 Native 堆,如果其他的 Java 对象使用不合理占用较多内存,仍然会发生 Java OOM

2 . 方案可能产生的影响?

Bitmap 的像素占用的内存转移到 Native 堆之后,会使得虚拟内存使用增多,当存在泄漏时,可能会导致 32 位应用的虚拟内存被耗尽(实际上这个表现和 Android8.0 之后系统的表现一致)。

所以,方案的目标实际是为了使老的 android 版本能够支持更复杂的应用设计,而不是为了解决内存泄漏。


我要回帖

更多关于 正在优化第一个应用 的文章

 

随机推荐