应用办公生活信息教育商业
投稿投诉
商业财经
汽车智能
教育国际
房产环球
信息数码
热点科技
生活手机
晨报新闻
办公软件
科学动态
应用生物
体育时事

百度APPiOS端内存优化实践内存管控方案

  一。hr背景
  随着业务的发展,百度APP有很多大内存业务场景如直播、短视频、小程序、百度识图等,通过线上页面统计数据得知超过150M页面有40个,耗内存最多的页面有400M。单个页面不会有内存或者稳定性问题,但是当用户浏览了很多页面之后,累加起来内存已经很高了,再加上我们为了追求秒开,经常采用的思路是以空间换取时间,从而导致APP处于一个内存高水位状态,在这种情况下如果打开一个大内存页面,中低端机极大概率会出现OOM类型的崩溃。
  内存管控方案应运而生,该方案重点解决的问题是在内存水位很高的情况下,保证APP稳定性又兼顾用户体验,延长APP使用时长同时避免OOM。
  该技术方案在百度APP于22年Q1顺利上线,随着基础服务层和越来越多的业务线接入,尤其是OOM频发的页面接入后,在降低OOM率方面发挥了重大作用,效果非常明显。
  二。hr技术方案综述
  内存管控整体方案架构图如下所示:
  实时监控APP内存:在APP运行阶段不断监控内存变化。重点关注两个问题,第一,选取合适的能反映APP内存的指标,第二、实时性必须满足要求,同时不能引入额外的性能问题。页面内存预测:根据历史经验和线上数据,我们可以预测将要打开新页面后APP占用内存大小,结合当前内存我们可以实时计算出应用新开当前页面后自身占用的内存大小,举个例子,当前页面占用内存400M,通过线上历史经验数据我们知道新页面需要占用内存是300M,那么新开一个页面后,APP内存700M。内存水位判断:根据对当前APP内存状态的监控,能够判断出用户内存所处的水位状态,如安全水位和危险水位,安全水位是指当前APP内存足够,可完全按照业务需求分配内存,危险水位是指目前APP很容易出现OOM,必须马上释放内存缓存。频率控制:因为每隔3S做一次内存检测,当处于危险水位时,会通知APP各个模块做内存释放,但内存释放也是需要时间的,并且不一定会立马降低到安全水位,如果接下来还是每隔3S通知各模块做内存释放,其实是一种资源浪费,频繁的内存释放操作会给APP性能带来损耗,所以通过频率控制模块既能最大限度地释放内存,又实现APP性能最小损失。危险水位报警:当APP的内存处于危险水位的状态时,会向基础服务层和业务两个层面发送报警通知,对于基础服务层来说,百度APP主要做了图片内存和NSURLCache内存自动回收,全局生效;对于业务层来说,主要针对内存大户且OOM率较高的页面做了内存释放操作,如小程序页面,收到内存报警时,会将缓存的处于非活跃状态的页面做清理操作,对于其他业务同样道理,清理业务自身的数据缓存和其他内存缓存。主动降级:是指业务层在分配较大内存时,先判断当前APP所属的内存水位等级,若处于危险水位,业务做降级分配较小内存,若处于安全水位,做全量内存分配。目前百度APP的识图和数字人业务已接入此方案,对于百度识图场景,做多模态图片识别加载算法模型文件较大,处于危险水位时加载兜底模型,以业务能用为标准,其他场景类似。
  三。hr与内存报警的区别
  目前iOS系统中存在类似的方案,专业名称为内存报警机制,当设备可用内存下降到到危险状态时,Mach系统的pageout守护程序会查询进程列表及其驻留页面数,向驻留页面数最高的进程发送NOTEVMPRESSURE,被选中的进程会响应这个压力通知,本质上就是APP收到系统的didReceiveMemoryWarning内存警告,APP释放部分内存达到降低手机内存负载的目标。有人会问iOS系统提供了内存报警通知,为什么我们还会做貌似类似的事情,这是因为我们对系统的内存报警机制做了如下两点补充:内存报警机制是内存极其危险的时候才发出的,尤其是对于低端机而言非常致命,因为APP来不及释放内存到安全水位就已经OOM了。在实践开发过程中,对低端机(iPhone8以下)测试结果发现,当收到内存报警时,APP实际可使用内存(可用内存减去已用内存)没有超过100M,但是目前手百APP大于150M页面就有40个,当收到内存警告前后,随便打开上述40个大页面中的任何一个页面,APP根本没有来得及处理警报应用就会崩溃。相反,百度APP内存管控方案在制定危险水位时考虑到这种情况,适当预留了较大空间,让APP更从容地释放内存。内存报警机制没有提供获取APP实时内存状态的功能,在实践中经常会遇到大块内存分配的场景,较为常见场景如在中低端机端智能场景中,加载大模型到内存时,因为不知道内存当前处于危险状态还是安全状态,分配较大内存会出现内存峰值瞬时上涨到高点,中低端机手机设备直接OOM,在整个过程中也根本没有收到过内存报警。内存管控方案弥补了这一不足,通过实时获取内存状态,不同机型不同设备设置不同危险水位级别,在分配较大内存时,先判断APP内存状态,若处于危险水位时,业务线开发可以走降级逻辑,降低对内存消耗,减少OOM风险。
  四。hr实时监控APP内存
  百度APP实时监控内存采用如下方案:在子线程开启定时器,每隔3S去采样一次内存physfootprint字段数据,以此作为衡量的内存的唯一指标,其他字段值一律不要获取,因为多增加一个变量会多增加CPU计算量。实践数据表明,第一、单次获取physfootprint耗时小于1us,每隔3S获取physfootprint没有引起CPU占比的涨幅,也就是说不会带来性能问题;第二、3S的采样周期实时性完全满足我们工程的要求,正常情况下,开启一个页面到页面可交互需要1。5S,采样周期如果太长,会存在页面内存已经飙升但是还没来得及做管控,采样周期太短会浪费过多的CPU资源。
  为什么我们选用physfootprint作为内存衡量指标,而不用其他字段,需要重点解释一下。iOS端所有的内存相关指标都集中在taskvminfo结构体中,下载XNU最新开源代码(https:opensource。apple。comsourcexnu),代码路径:osfmkmachtaskinfo。h,具体字段值如下所示:structtaskvminfo{machvmsizetvirtualsize;virtualmemorysize(bytes)integertpagesize;machvmsizetresidentsize;residentmemorysize(bytes)省略machvmsizetphysfootprint;省略}
  iOS开发演变的这几年历程中,受Android端内存指标影响,我们先后使用过各种内存指标,常见的如virtualsize(虚拟内存)、residentsize(驻留内存)和physfootprint,那究竟使用哪个指标是合理的?我们知道iOS使用的是低内存清理机制叫Jetsam,这个机制有点类似于Linux的OutofMemory杀手,当内存压力过大时,Jetsam会把一些优先级不高或者占用内存过大的进程杀掉。就是说内存处于危险状态时Jetsam决定kill哪个进程,因此Jetsam衡量内存水位指标绝对是众多内存指标中最为合理的一项,接下来我们看Jetsam机制源码。
  我们再次回到XNU源码中,查看代码bsdkernkernmemorystatus。c,重点查看函数memorystatuskillhiwatproc,这是jetsam核心代码,用于kill高内存分配进程的关键函数,具体实现如下所示:staticbooleantmemorystatuskillhiwatproc(uint32terrors,booleantpurged,uint64tmemoryreclaimed){nextpmemorystatusgetfirstproclocked(i,TRUE);while(nextp){省略footprintinbytesgettaskphysfootprint(ptask);skip(footprintinbytesmemlimitinbytes);if(skip){continue;}else{memorystatuskillproc(p,kMemorystatusKilledHiwat,jetsamreason,killed,footprintinbytes);省略}}
  首先通过memorystatusgetfirstproclocked去优先级队列里面取出优先级最低的进程,如果内存超过阈值,将通过memorystatuskillproc杀掉这个进程,否则跳过取下一个进程。我们看到Jetsam是通过gettaskphysfootprint方法获取内存水位来决定是不是需要kill该进程,因此使用physfootprint作为APP内存指标是最合适的。
  关于physfootprint的定义,我们回到XNU源码中,查看代码osfmkkerntask。c,有physfootprint的注释定义。Physicalfootprint:Thisisthesumof:(internalalternateaccounting)(internalcompressedalternateaccountingcompressed)iokitmappedpurgeablenonvolatilepurgeablenonvolatilecompressedpagetable
  physfootprint(internalalternateaccounting)(internalcompressedalternateaccountingcompressed)iokitmappedpurgeablenonvolatilepurgeablenonvolatilecompressedpagetable。
  字段
  具体含义
  internal
  在iOS中表示的就是residentsize驻留内存
  internalcompressed
  iOS上没有交换空间机制,取而代之使用Compressedmemory,是在内存紧张时能够将最近使用过的内存占用压缩至原有大小的一半以下,并且能够在需要时解压复用
  iokitmapped
  io设备映射占用的内存,其实是不能使用purgeablememory的部分
  alternateaccounting
  iokit映射占用的dirty页
  pagetable
  虚拟地址映射表内存
  purgeablenonvolatile
  下面重点介绍
  purgeable内存是iOS系统为开发者提供的一层cache机制,分为volatile、empty和nonvolatile三种类型,volatile表示该内存资源是暂时不被使用的,系统将在内存吃紧的时候回收掉它,使用这种类型资源前要查询是否已经无效了(变成empty状态);empty表示该内存资源明确不用了需要立即释放;nonvolatile表示该内存资源一直有用,不能被回收。volatile和empty状态的资源不计入进程自己的memfootprint,它算系统的cache内存,nonvolatile会算自己进程的内存,被虚拟内存系统回收时不会被换出到磁盘,所以physfootprint在计算内存时,只计算了nonvolatile类型,对于volatile、empty没做计算。
  五。hr页面内存预测
  为了能够更精准的对页面的内存进行分析和预测,我们在实时内存监控的基础上,开发了页面内存预测方案。具体来说,在前面通过定时器我们知道了每隔3S手机APP内存状态,本方案通过经验数据直接预测未来一段时间内存的涨幅,让业务线可以更加从容的释放内存。我们知道当新打开一个页面时存在内存飙升的情景,这个时候3S的采样周期未到,内存已经上涨很多,内存管控方案还未生效APP极有可能已经OOM了。我们的方案是通过页面内存计算,在打开新页面前一刻,就知道接下来页面内存可能会涨到多少,如果进入危险水位,实时释放内存以降低OOM率,通过这种精细化处理进一步提前降低内存峰值。
  页面内存计算方案如下所示,首先,当前页面是P1页面,当有页面跳转发生,将要通过push操作进入到P2页面时,记录当前百度APP内存physfootprint值为M1,当从P2页面同样发生跳转到其他页面时,记录百度APP内存physfootprint值为M2,那么M2M1为P2页面内存。
  注意,我们只通过push方式统计了页面内存,没有通过pop方式统计,有两个原因,第一、通过线上数据发现,pop方式时因页面已经打开,并且会创建单例导致内存统计存在很多badcase,push方式时页面从未创建也不会有单例,数据相对准确;第二、通过push方式已经可以覆盖所有页面了,pop方式不需要统计。
  六。hr制定内存水位
  关于内存水位的制定直接决定了本方案实际收益的大小,水位阈值制定太小会导致频繁的内存管控影响业务效果,水位阈值制定的太大,与实际的Jetsam水位线偏离过大,导致内存管控无法生效,可能会出现APP已经OOM了,管控方案还没生效,水位线的制定非常关键。
  关于危险水位线的制定,必须结合Jetsam原理,目前苹果官方没有公开Jetsam水位的文档,业界有如下方法解决方案。丨6。1通过Jetsam日志获取
  具体来说从手机设置隐私分析与改进分析数据这条操作路径中,可以拿到JetsamEvent开头的日志。这些日志中就可以获取一些关于App的内存信息,查找崩溃原因时需要关注perprocesslimit部分的rpages,其中rpages代表进程占用的内存页数量。pageSize代表当前设备物理内存页的大小,在JetsamEvent开头的系统日志里可以找到pageSize的值,那么pageSizerpage的值代表目前该进程OOM时使用的内存大小,可作为进程可用内存的上限。
  实际操作过程中,发现此方法可操作性不强,因为同一台手机不同的JetsamEvent日志rpages值变化太大,用iphone12的测试结果显示,从400到800都有,pageSize是固定值16384Byte,按照最高值计算当前App的内存限制值:pageSizerpages10241024163848001024102412。5M,按这个结果iphone12最大的内存阈值是12。5M,置信度明显有问题。
  丨6。2通过XNU源码获取内存水位阈值
  首先必须越狱手机获取root权限,通过XNU源码中的数据结构、宏定义和函数获取OOM阈值,参考XNU最新开源代码(https:opensource。apple。comsourcexnu),代码路径:bsdsyskernmemorystatus。h,关键数据结构memorystatuspriorityentry,定义如下,其中pid代表进程标识,priority代表JetSam中的优先级,limit就是我们要找的水位线上线。同时,在文件kernmemorystatus。h有如下跟进程优先级相关的宏命令,其中通过MEMORYSTATUSCMDGETPRIORITYLIST宏定义可以获取进程的优先级列表以及每个进程的内存水位线。typedefstructmemorystatuspriorityentry{pidtpid;int32tpriority;uint64tuserdata;int32tlimit;uint32tstate;}memorystatuspriorityentryt;defineMEMORYSTATUSCMDGETPRIORITYLIST1defineMEMORYSTATUSCMDSETPRIORITYPROPERTIES2defineMEMORYSTATUSCMDGETJETSAMSNAPSHOT3defineMEMORYSTATUSCMDGETPRESSURESTATUS4省略
  最后通过调用系统函数memorystatuscontrol的实现可获取memorystatuspriorityentry结构体值,其中limit字段代表水位线,代码路径:bsdkernkernmemorystatus。cintmemorystatuscontrol(structprocpunused,structmemorystatuscontrolargsargs,intret){省略switch(argscommand){caseMEMORYSTATUSCMDGETPRIORITYLIST:errormemorystatuscmdgetprioritylist(argsbuffer,argsbuffersize,ret);break;省略}
  实践证明这种方法是可行的,唯一缺点是需要获取root权限,我们要获取不同机型的内存阈值,需要将这些设备全部越狱。丨6。3百度APP采用的技术方案
  百度APP采用的方案是综合百度APP自身的线上业务数据,采用主动触发OOM获取内存阈值方案,结合多方数据最后确定内存危险水位阈值。丨6。3。1内存数据摸底
  通过线上内存采样打点,获取了百度APP不同机型在使用过程中的内存值,然后经过服务端数据聚合,我们明确知道了百度APP在没有发生OOM情况下不同机型的内存最大值,这份线上数据很重要,虽然不是内存阈值的,但是内存阈值肯定是高于该值的。丨6。3。2页面内存数据统计
  技术方案在第五节做过详细介绍,这儿不再赘述,通过服务端对页面内存数据挖掘后,我们明确知道了不同机型新开一个页面时最大的内存涨幅。丨6。3。3主动触发OOM获取内存值
  开启定时器任务每隔1S分配20M内存,示例代码如下所示:intsize2010241024;charinfomalloc(size);memset(info,1,size);
  同时监控内存变化,在控制台输出,随着可用内存越来越少,触发Jetsam机制,直到发生OOM,从而得到OOM前内存阈值。(int64t)memoryUsage{int64tmemoryUsageInByte0;structtaskvminfoinfo;machmsgtypenumbertsizeTASKVMINFOCOUNT;kernreturntkerrtaskinfo(machtaskself(),TASKVMINFO,(taskinfot)info,size);if(kerrKERNSUCCESS){memoryUsageInByteinfo。physfootprint;}returnmemoryUsageInByte;}丨6。3。4确定内存管控危险水位阈值
  经过前面三个步骤,我们获取了不同机型的三个阈值,分别是内存数据摸底阈值、页面内存阈值、主动触发OOM获取的阈值,为了让业务更从容地释放内存,内存管控阈值为主动触发OOM获取的阈值减去页面内存阈值,如果该值小于内存数据摸底阈值,那么内存数据摸底阈值就是该机型内存管控阈值。
  百度APP采用的这个技术方案不需要越狱手机,通过主动触发OOM获取的阈值体现了Jetsam机制,更具有可操作性;同时结合自身线上数据,针对手百场景定制化挖掘。
  七。hr总结
  最后,总结百度APP内存管控方案具有如下特点:针对不同机型制定了相应的内存水位可以更加从容地释放内存。本技术方案结合Jetsam机制和百度APP线上内存数据,制定了iPhone各机型允许使用的内存水位线,给业务和框架更大的空间释放和清理内存。实时内存监控和精细化页面内存预测,在实时内存监控的基础上,开发了页面级的内存度量方案,可以估算出用户在新开一个页面内存涨幅多少,在未来一段时间内存会不会达到危险水位。内存管控方案提供主动和被动通知两种方式获取内存水位状态,实现了各业务层根据手机内存情况实时降级,时效性更强,跟之前服务端降全量降级方案相比,更加灵活,性能更好。
  该方案上线后,随着Q2基础服务层和业务线接入,实现OOM降低一半的收益,并且业务层接入成本很低,后续会推动更多内存大户和OOM频发的页面接入。感谢各位阅读至此,如有问题请不吝指正。
  八。hr参考链接
  〔1〕、OOM探究:XNU内存状态管理:https:www。jianshu。comp4458700a8ba8
  〔2〕、XNU源码:https:opensource。apple。comsourcexnu
  〔3〕、《深入解析MacOSXiOS操作系统》
  〔4〕、iOSOutOfMemory原理阐述及方案调研:https:juejin。cnpost6844903749836603400heading7
  作者:RichardYang
  来源:微信公众号:百度App技术
  出处:https:mp。weixin。qq。comsdETOGD3NYU2SdZhxGu0SZg

早安心语文案图片正能量句子没有所谓的运气,只有绝对的努力有一种姿态,让自己活得无可替代,没有所谓的运气,只有绝对的努力。早安,加油!在我们人生的每一个阶段,真正重要的不是你身处何处;而是你要往何处走,有些路走起来艰涩坎坷,有些……世界杯最离奇剧本!小说都写不出来,梅西一诺千金,莱万差点回家北京时间12月1日,世界杯至今为止,最疯狂、最让人意想不到的剧情终于上演了。阿根廷所在的C组现在已经正式确定了晋级的球队,梅西带队实现了奇迹大逆袭,从之前的小组垫底一路飙……俩小伙恶作剧纵火,导致牢狱之灾许多家长十分重视孩子的学习成绩,这是无可厚非的。但是,在家庭教育中,也千万不能放松遵纪守法的教育。11月22日,今日说法栏目中,淄博市二位刚刚参加工作,二十出头的年轻人,……iPhone14订单异常增加?专家苹果准备清库存,价格还会下今年iPhone14标准版与Plus版表现不佳,发布后销量未能达到预期,一度向供应链下达命令大幅削减订单,价格跳水打破历史纪录。最新消息却显示,两款机型订单突然异常增加,明显与……苏提达造型大翻车,身穿奶奶装又土又村,裙子上还堆满褶皱苏提达造型大翻车,身穿奶奶装又土又村,裙子上还堆满褶皱玛哈哇集拉隆功的后宫备受关注,到底谁最受宠,外界一直争论不休。但是可以肯定的一点是,苏提达能够坐稳自己的位置,并非是……2022。11。20新版早安问候语图片丨周末温馨祝福丨朋友圈早上好,祝你今天身体百威,运气喜力,心情世好。总之,清清爽爽,快快乐乐每一天!有一种期盼叫早安,有一种快乐叫早安,有一种兴奋叫早安,有一种轻松叫早安,还有一种问候叫早安,……肺癌有哪些食物要忌口?肺癌饮食要注意什么?肺癌是一种比较常见的癌症,而且在我国的肺癌的发病率是越来越高了。在发生肺癌之后,对于患者的身体也是有一定的影响的,那么肺癌饮食要注意什么呢?肺癌有哪些食物要忌口?下面就为大家详……剖腹产后胸口疼好几根肋骨骨折了9月份,王女士做了剖腹产手术,喜得千金。但之后,说是一直胸口疼。CT结果显示,她有好几根肋骨骨折了。视频:二胎剖腹产后胸口疼,拍片发现肋骨骨折王女士:术后醒来之后,……安徽工程大学举办首届研究生人工智能创新大赛【来源:安徽省教育厅高等教育】11月13日,由安徽工程大学研究生部主办,电气工程学院、人工智能研究院承办的首届研究生人工智能创新大赛评审会在该校图书馆综合楼举行。经过激烈……中年人喜欢喝酒无伤大雅,但这2件事,千万别做,容易让人嫌弃如果仅把社会上的人士分为青年人,中年人和老年人三个群体的话,那么毫无疑问的是中年人是最喜欢喝酒的一代。这是从多个方面去考量的,毕竟中年的时候他们已经没有了太过于年轻精力旺盛的身……去云南昆明逛菜市场,物价集体飞涨,游客真是不敢相信引导语相信不少人对于外地的一些生活习惯可能并不太了解,如果去到外地游玩或者是生活的时候,可能都会被当地的一些比较有特色的生活习惯所震撼。毕竟每个地方都有当地人早已习惯或者……豫法品读丨你的坚持,终将美好朗读者:延津县法院徐冰晶回望过去的一年,我们收获过、欣喜过,也跌倒过、迷茫过,但我们一直在往前走,不停留。无论顺风顺水也好,逆水行舟也罢,请相信,你的坚持,终将美好。……
2021,它们都翻车了?春天来了,又到了。。。。。。新手机发布的季节。随着高通、联发科旗舰SoC的推出,各大智能手机厂商已经蓄势待发,要从本月开始掀起旗舰手机更新换代的潮流。前事不忘,后事之师。……DNF,不懂的可以去问别人,但是玩游戏一定要自己说了算今天我们来聊一聊DNF游戏中不氪金的游戏体验如何?从2009年到至今不氪金的DNF给我的体验,说是不氪金,时间就是金钱,投入的时间换算其他工作学习的时间是一笔不小的收入。针对游……上地这个园区秋色正好快来打卡吧!夏日尘埃落定,秋日缓缓展开。这时候,中关村软件园的植物似乎也暗藏着量子纠缠,在变老,也在成熟。季节的流转中,始终藏着一颗不可逆的心。……黑龙江有哪些景点值得你去路过这个充满俄罗斯风情的横道河子小镇,差点让我停下来促足欣赏,这个朴实无华却又充满艺术氛围小镇,真的很美,但时间不容观望,只好随手拍几张照片聊以慰藉。说起横道河子这个小镇……2日CBA赛事,辽宁浙江赢弱旅,范子铭VS沈梓捷,北京队拒绝时间来到11月2日,CBA第七轮继续进行,这一天迎来比赛高峰,有6场值得球迷关注,可惜没有四强内的对话,不过几个实力接近的老对手相遇,也会打的比较有看点,其中以北京首钢对深圳最……蒋介石原配毛福梅被蒋介石家暴流产,离婚后以姐弟名义相处人们都知道蒋介石夫人是宋美龄,这位跨越三个世纪的民国第一夫人的传奇人生也被人们津津乐道。但是更多的人不知道,蒋介石的第一位夫人其实名叫毛福梅,也就是蒋经国的生母亲。毛福梅……蒸馒头是冷水上锅还是热水上锅?牢记这几点,馒头暄软不塌陷我一直认为河南的馒头是最好吃的,麦香味足,用手一层一层地撕着吃,又筋又香还有嚼头。从小吃到大,一天都不能少,特别是刚出锅的热馒头真是吃不够。我也在南方生活过近20年,南方……怎么用诗经取一眼沦陷的新生儿名,颇有江南烟雨中的古风小调关注《吉生起名》小程序,免费起名(中文名、英文名、小名乳名、查重名、汉字五行)。(此处已添加小程序,请到今日头条客户端查看)人名是一种语言现象,那么,对人名的研究就……将继承3000亿财产!湖南弃婴实现人生逆袭,与世界首富成一家说到网购,想必很多人最先想起的就是电商,那么世界上最大的电商品牌又是哪个呢?没错,就是大家耳熟能详的亚马逊。有人会不经意地把它和我国的阿里巴巴做起对比,但不可否认的是,这两年的……莱科葫芦里卖的什么药!宁愿用傅欢踢主力,都不想给他出场机会上海上港在足协杯上表现不错,球队经过一段时间的调整,就取得了晋级四强的成绩。这让上港主帅莱科的执教能力,再次得到了球迷认可。莱科在带上港出战足协杯时,也是培养了新人,同时给一些……但求无悔棋院中国象棋入门第一课心算练习(三十六)想提高象棋的水平吗?对局中想给对方设下陷阱吗?想瞬间识破对方的骗招吗?象棋的心算是实现这些想法的基础。如何提高心算?第一步就是练习连将杀,而练习连将杀不应该只是简简……这个饼,给我原地封神!请把嘴巴寄过来我妈吃了一口,直接告诉我让我在小区出摊,哈哈哈,关键是不用擀面的,相信我,超市的饺子皮足够了,我真的会拴q好嘛!但是小编真的真的超爱这个皮包酥脆、香辣过瘾的千层牛肉饼!做……
友情链接:快好找快生活快百科快传网中准网文好找聚热点快软网