第十二课 Unity 内存优化_内存工具篇(Memory)详解

内存(Memory)

unity 内存部分也是优化过程中非常重要的一个环节,也会影像渲染过程中的同步等待与带宽问题。因此内存的优化也可能会给我们渲染开销带来精简,今天我们先来了解unity中的内存与使用到的内存工具。

Unity中的内存

  • 托管内存:主要是指使用托管堆或者垃圾收集器自动分配和管理的内存也包括脚本堆栈与虚拟机内存。
  • C#非托管内存:可以在C#与Unity Collection名字空间和包结合使用,不使用垃圾收集器管理的内存部分。如果使用数据结构,不建议使用system下的collection的数据结构,而是要使用unity collection下的数据结构进行开发。
  • Native 内存:Unity 用于运行引擎的C++内存。

性能分析工具

下面我们聊一聊unity引擎提供了哪儿些内存方面的工具

  1. Unity Profiler下的Memory标签:这里显示了unity当下内存使用的追踪状态,包括各类内存的分配和使用情况,以及当前unity下分配的对象与资源占用的内存情况。2021以后版本,profiler不再提供对象抓取快照功能了。而是使用memory profiler 直接抓取内存快照了。
  2. Memory Profiler:我们可以通过它来抓取内存快照,也可以对比两个内存快照下unity对象与资源的差异。通过Tree Map来查看内存分配的视图。通过Object and Allocation标签查看具体对象内存快照,并可以通过链接直接找到原工程中对应的资源和对象,通过fragmentation标签可以查看内存片段,unity2022以后 memory profiler变得更加简洁了,针对native内存甚至可以查看到具体是分配到哪儿个allocators中的。
  3. Memory Settings中的设置:大家现在可以在权衡时间和空间维度上的性能指标做更精准的设置了。
  4. UPR中的内存快照功能:主要是针对移动设备,当你使用UPR做性能调试时会经常用到,它可以脱离unity编辑器,在运行时抓取内存信息与对象分配信息,并可以做到多帧对比。具体操作请参阅UPR手册,后期我们可能会单独做写一个帖子,纯翻译供大家阅读。
  5. mac或者ios上我们可以选择xcode提供的instrument下的allocation工具。
  6. android上可以使用android相关的系统命令或者android studio profiler工具。
Profiler-Memory

Total Memory Breakdown(总内存分解)

  • ManagedHeap:托管堆,重点监控对象,不要让它超过20MB,否则可能会有性能问题!
  • Graphics & Graphics Driver:驱动程序在纹理、渲染目标、着色器和网格数据上使用的估计内存量。
  • Audio:音效及声音文件,重点优化对象,播放时长较长的音乐文件需要进行压缩成.mp3或.ogg格式,时长较短的音效文件可以使用.wav 或.aiff格式。
  • Video:视频系统的估计内存使用量。
  • Other:显示Unity跟踪的本机内存,但不在特定计数器下报告。
  • Profiler:探查器功能从系统中使用和保留的内存。

Objects Status(对象状态,显示通常占用大量内存的资源类型(纹理,网格,材质,动画剪辑)的对象实例数量,以及它们在内存中的累积大小(资源,游戏对象,场景对象))

  • Texture2D: 2D贴图及纹理。重点优化对象,有以下几点可以优化:

    1.许多贴图采用的Format格式是ARGB 32 bit所以保真度很高但占用的内存也很大。在不失真的前提下,适当压缩贴图,使用ARGB 16 bit就会减少一倍,如果继续Android采用RGBA Compressed ETC2 8 bits(iOS采用RGBA Compressed PVRTC 4 bits),又可以再减少一倍。把不需要透贴但有alpha通道的贴图,全都转换格式Android:RGB Compressed ETC 4 bits,iOS:RGB Compressed PVRTC 4 bits。

    2.当加载一个新的Prefab或贴图,不及时回收,它就会永驻在内存中,就算切换场景也不会销毁。应该确定物体不再使用或长时间不使用就先把物体制空(null),然后调用Resources.UnloadUnusedAssets(),才能真正释放内存。

    3.有大量空白的图集贴图,可以用TexturePacker等工具进行优化或考虑合并到其他图集中。

    4.存在空白的或者纯色的贴图,可以用颜色节点代替

  • Mesh:场景中使用的网格模型,注意网格模型的点面数,能合并的mesh尽量合并。
  • Materials:加载的材质和它们使用的内存的总数。
  • AnimationClip: 加载的动画和它们使用的内存的总数。

Assets(已加载资产的总数)

  • Game Objects:游戏对象总数
  • Scene Objects:这个数字包括游戏对象的数量,加上组件的总数,以及场景中所有不属于资产的东西。
  • GC allocated in frame:显示选定帧中托管分配的数量及其总大小(以字节为单位)。

Memory Profiler

主要用来查看托管内存和本机内存的详细分配情况。它通过捕获、检查、比对内存快照的方式来检测内存泄漏和内存碎片。本篇文章中使用的版本是0.7.1版本。

安装

add PackageManager- >Add By Name- >输入com.unity.memoryprofiler 

查看

Windows - > Analysis - > Memory Profiler

Memory Profiler界面,可以链接真机检测,也可以在Editor检测。

点击Capture  New Snapshot截取保存当下帧的内容

点击上图中3号的位置Snap来查看详细的内容

通过观察,我们能看到上图的数据与Profiler中的Memory的数据是一致的

单帧检测

一般去看工程内的资源, 去检查占用内存特别大的游戏对象。

Memory Breakdowns界面可以查看unity内的具体游戏对象,也同样可以进行筛选

TreeMap界面进行检查, 这里已经分好类, 同时可以根据Size的大小进行排序,查看内存占用较大的游戏对象进行优化处理。

Fragmentation 页签进行查看, 点击对应的地址块,下方可显示详细信息。

1.该视图会将内存数据可视化成虚拟内存布局。如下图所示:

 2.每一行都会显示一个内存块和起始地址标签。当起始地址标签上面有黑色背景时,就表明该起始地址就是内存块的开始部分,并且与之前的内存块之间存在不连续性;否则,就表明该起始地址就是内存块的一部分。如下图所示:

3.既可以通过单击起始地址标签来选择关联的内存块;也可以通过单击鼠标拖动的方式来选择感兴趣的内存块;甚至可以通过单击内存块中的虚拟内存来选择该内存块。

4.当选择内存块时,就会在Filters面板中将相关的虚拟内存按照指定的列表类型(区域列表-Regions list、分配列表-Allocations list、对象列表-Objects list)进行展示详细信息。

区域列表类型展示信息如下图所示:

分配列表类型展示信息如下图所示:

还有对象列表类型展示信息,操作同上。

Objects and Allocations页面可查看详细的对比内容,可以进行筛选

筛选方式:Select Table View

筛选之后就可以进行详细分析了,可以通过Type,Size, Referenced By等标签查看对应的游戏对象。

也可以鼠标右键点击下图1或者2来对类型和名字进行具体筛选。

两帧对比检测

一般使用两帧率对比用于检测内存泄漏。

在要对比的节点分别进行Capture  New Snapshot截取, 点击Compare Snapshots进行对比,在分别点击两个Snap,进行对比。

Summary页签可看汇总的对比内容:

Objects and Allocations页面可查看详细的对比内容,可以进行筛选

筛选方式:Select Table View来查看以下几种类型数据:

  • [Diff] Raw Data:从原始数据列表中选择一项原始数据(Root Reference、Native Allocation、Native Object等)进行查看。
  • [Diff] All Managed Objects:查看所有的托管对象(IL2CPP、Mono)。
  • [Diff] All Native Objects:查看所有继承自Unity.Object类型的本机对象。
  • [Diff] All Objects:查看所有本机对象和托管对象。
  • [Diff] Alloc:从分配列表中选择一项分配数据(ByNativeObject、ByRoot、ByMemRegion)进行查看。

筛选之后就可以进行详细分析了,可以通过Type,Size, Referenced By等标签查看对应的游戏对象。

也可以鼠标右键来对类型和名字进行具体筛选。

总结

MemoryProfiler 是一个非常好用的检查内存问题的工具,以下问题都可以通过该工具进行排查

  • 查找有问题的游戏资源,例如:Mesh和贴图非常大的美术资源
  • 内存泄漏问题

检测内存占用:可以使用Unity Memory Profiler来检测托管内存和本机内存的占用情况。检测流程如下所示:

  1. 首先打开Unity Memory Profiler窗口;然后打开想要检查的内存快照;最后在主视图区域以树形视图的方式来显示内存快照中深度内存数据。
  2. 查看树形视图中不同的对象类别。
  3. 单击树形视图中某一个对象类别,此时会展开该对象类别中所有的对象以及在主视图区域下方以对象表格的方式来显示该对象类别中所有的对象。
  4. 单击对象类别中某一个对象或者单击对象表格中某一个对象,进而可以在对象表格中查看该对象的具体信息。
  5. 首先将对象表格中所有的对象按照从高到低的顺序进行排序;然后优先从纹理、着色器变体、预分配缓冲区这三种对象来制定好减少内存的目标。

检测内存泄漏:可以使用Unity Memory Profiler来检测托管内存和本机内存的泄漏情况。如下所示:
1.出现内存泄漏的危害如下所示:

  • 应用程序可能因为GC遍历对象时间变长的原因而出现卡顿现象。
  • 应用程序可能因为可用内存空间不足的原因而出现闪退现象。

2.出现内存泄漏的原因如下所示:

  • 对于自动垃圾回收而言,对象的引用计数不为0。
  • 对于被动垃圾回收而言,对象没有被代码手动释放。

3.查找并修复场景卸载后发生的内存泄漏:流程如下所示:

  1. 使用Unity Memory Profiler来设置捕获目标。
  2. 首先在捕获目标上加载一个空场景;然后在该场景上拍摄一张内存快照。
  3. 首先在捕获目标上加载一个要检测内存泄漏的场景;然后在该场景上执行业务模块;最后将该场景卸载(调用Resources.UnloadUnusedAssets函数)掉或者切换到一个空场景。
  4. 在捕获目标上再拍摄一张内存快照。
  5. 为了避免处理内存快照文件和捕获目标之间竞争系统资源,建议此时关闭掉捕获目标。
  6. 首先在工作台区域打开第一张和第二张内存快照文件;然后单击Diff按钮来对两个打开的内存快照进行差异比对;最后将差异比对生成的数据显示在主视图区域中。
  7. 首先在主视图区域中选择Diff表格属性;然后选择Group排序规则来将相同值(Deleted、New、Same)的对象合并在一个组内;最后查看数值为New的分组,如果存在对象是在第二张内存快照中的话,就表明该对象的内存泄漏了。

4.查找并修复小的连续分配可能造成的内存泄漏:流程如下所示:

  1. 使用Unity Memory Profiler来设置捕获目标。
  2. 首先在捕获目标上加载一个要检测内存泄漏的场景;然后在该场景上拍摄第一张内存快照。
  3. 首先播放要检测内存泄漏的场景;接着在该场景上拍摄第二张内存快照;然后继续播放该场景;最后在该场景上拍摄第三张内存快照。
  4. 为了避免处理内存快照文件和捕获目标之间竞争系统资源,建议此时关闭掉捕获目标。
  5. 首先在工作台区域打开拍摄的第二张和第三张内存快照文件;然后单击Diff按钮来对两个打开的内存快照进行差异比对;最后将差异比对生成的数据显示在主视图区域中。
  6. 首先在主视图区域中选择Diff表格属性;然后选择Group排序规则来将相同值(Deleted、New、Same)的对象合并在一个组内。
  7. 首先在主视图中选择Owned Size表格属性;然后选择Group和Sort Descending排序规则来将相同值的对象合并在一个组内,并按照从大到小的顺序来排列组。
  8. 查看较大内存分配组中的对象是否同时存在于Same组和New组中,记录好满足条件的对象。
  9. 首先在工作台区域打开拍摄的第一张和第二张内存快照文件;接着单击Diff按钮来对两个打开的内存快照进行差异比对;然后将差异比对生成的数据显示在主视图区域中;最后执行4.6 ~ 4.8步骤,进而了解系统内潜在的内存泄漏。

元数据:如下所示:
1.元数据类型为MetaData,包含的字段如下所示:

  1. content:包含项目名称和捕获目标为Unity Editor时的脚本版本。
  2. platform:应用程序对应的目标平台。
  3. screenshot:针对捕获目标截取的屏幕截图(像素大小小于480x240)。

2.首先在捕获目标上拍摄内存快照时就会生成元数据;然后该元数据会自动添加到内存快照中;最后开发人员可以通过元数据来更好地了解内存快照的内容。
3.拍摄内存快照的方式如下所示:

  1. 当项目中有安装Unity Memory Profiler时,此时就可以在工具栏区域中点击Capture控件来针对捕获目标来拍摄一张内存快照。
  2. 在代码中通过MemoryProfiler.TakeSnapshot/TakeTempSnapshot函数来针对捕获目标拍摄一张内存快照。在调用该函数时,可以设置包含内存快照文件路径字符串和是否拍摄成功布尔值两个参数的结束回调函数。

4.生成元数据的方式如下所示:

  1. 当项目中没有安装Unity Memory Profiler时,此时可以首先给MemoryProfiler.createMetaData委托注册一个监听函数;然后在该监听函数中设置元数据。
  2. 当项目中有安装Unity Memory Profiler时,此时就会生成默认的元数据。
  3. 当项目中有安装Unity Memory Profiler时,此时就可以首先创建一个继承自MetadataCollect类型的元数据收集类型;然后在该类型里面重写CollectMetadata函数;最后在该函数中设置元数据。

项目中可能遇到的问题

首先要明确一点,在Editor中运行时,“Unity”大是正常的,因为在Editor中运行项目时,引擎包含了所有的资源占用的内存(除了部分纹理和Mesh是在GFX中),同时自身会进行很多的辅助操作来记录各种游戏运行信息。一般来说,在查看游戏运行时的真实消耗内存,我们均是推荐直接在发布游戏上通过Profiler进行查看,在Editor中运行游戏所看到的内存是要大很多的。


1.Device.Present:

  1. GPU的presentdevice确实非常耗时,一般出现在使用了非常复杂的shader.
  2. GPU运行的非常快,而由于Vsync的原因,使得它需要等待较长的时间.
  3. 同样是Vsync的原因,但其他线程非常耗时,所以导致该等待时间很长,比如:过量AssetBundle加载时容易出现该问题.
  4. Shader.CreateGPUProgram:Shader在runtime阶段(非预加载)会出现卡顿(华为K3V2芯片).
  5. StackTraceUtility.PostprocessStacktrace()和StackTraceUtility.ExtractStackTrace(): 一般是由Debug.Log或类似API造成,游戏发布后需将Debug API进行屏蔽。

2.Overhead:

  1. 一般情况为Vsync所致.
  2. 通常出现在Android设备上.

3.GC.Collect:

原因:

  1. 代码分配内存过量(恶性的)
  2. 一定时间间隔由系统调用(良性的).

占用时间:

  1. 与现有Garbage size相关
  2. 与剩余内存使用颗粒相关(比如场景物件过多,利用率低的情况下,GC释放后需要做内存重排)

4.GarbageCollectAssetsProfile:

  1. 引擎在执行UnloadUnusedAssets操作(该操作是比较耗时的,建议在切场景的时候进行)。
  2. 尽可能地避免使用Unity内建GUI,避免GUI.Repaint过渡GCAllow.
  3. if(other.tag == a.tag)改为other.CompareTag(a.tag).因为other.tag为产生180B的GC Allow.
  4. 少用foreach,因为每次foreach为产生一个enumerator(约16B的内存分配),尽量改为for.
  5. Lambda表达式,使用不当会产生内存泄漏.

5.尽量少用LINQ:

  1. 部分功能无法在某些平台使用.
  2. 会分配大量GC Allow.

6.控制StartCoroutine的次数:

  1. 开启一个Coroutine(协程),至少分配37B的内存.
  2. Coroutine类的实例 -> 21B.
  3. Enumerator -> 16B.

7.使用StringBuilder替代字符串直接连接.

8.缓存组件:

  1. 每次GetComponent均会分配一定的GC Allow.
  2. 每次Object.name都会分配39B的堆内存.

9.ManagedHeap.UsedSize是项目逻辑代码在运行时申请的堆内存,该选项只能通过优化代码来进行降低。 优化方法一般如下:

  1. 尽可能地复用变量,减少new的次数;
  2. 使用StringBuilder代替String连接,使用for代替foreach;
  3. 对于局部变量或非常驻变量,尽可能使用Struct来代替Class。

ManagedHeap.UsedSize过大,一方面可能会影响一次GC的耗时;另一方面也可能反映出脚本中不合理的GC Alloc。

10.有些小伙伴会发现System.ExecutableAndDlls占内存巨大,且一直在增长,是怎么回事?

System.ExecutableAndDlls该项显示的是执行文件和所调用的库(物理、渲染、IO等系统库)的总和。开发团队不用太担心该选项的数值,因为很多应用均在共用这些库,并且它对于真实项目的内存压力非常小,几乎没有影响,而且OS也不会因为该内存而杀掉游戏或应用。

11.凡是在Unity Profiler中能看到的资源就会保留在内存中。对于这种资源,在切换场景时调一下UnloadUnusedAssets API就可以释放。

12.Profiler.BeginSample统计到的数据与直接看Memory下的不一样,前者比后者的数据更大,这怎么理解?

这种情况确实也是经常会遇到的。一帧中分配如此高的内存是会触发GC.Collect的,而Mono中显示的数值则是GC之后的Mono内存数值。

13.正常情况下游戏如果一直玩下去,Mono是不是会一直增加? 比如频繁打开一个界面,界面里有脚本会不断创建一些东西 ,那么Mono是否会不断增加?对性能上会不会造成影响呢?

在除开启IL2CPP功能的应用中,Mono 确实是不会下降,但并不应该一直上升。
创建出来的东西,如果被引用在一个容器里,或者被某些脚本的变量引用,那么这部分堆内存就释放不掉;但如果没有被任何容器或者变量引用(比如,临时拼一个 String),那么这部分堆内存会在 GC 的时候释放(释放是指变为空闲的堆内存,堆内存的总量是不会下降的)。
对于后者,频繁地 new 对象虽然不会一直增加堆内存,但是会加速 GC 调用的频率,所以同样是需要尽量避免的。

14:我想请教一下,下图这个函数中,每次我都申请了一个List temp = list();在这里存放6KB的数据,但是如果不做GC处理,这6KB是否就一直累加,直到做GC处理了才会释放掉,是这样么?如果调用次数很多,每次都调用一点点,也会推高内存占用吗?
请输入图片描述

是的,这个6KB堆内存会随着Update的执行一直分配内存,所累积的堆内存会在GC触发时进行销毁。一般来说,研发团队需要尽可能避免在高频次调用函数中进行堆内存的分配。

15:在进行内存优化时,Unity Profiler给出的数据和Android系统(adb dumpsys meminfo,已经考虑memtrack的影响 )的数据差距较大(已经分析了Profiler自身的内存占用),如何分析这部分差异,比如包括对显存消耗进行准确统计,OS消耗的统计等等?

内存差异较大是正常的,一般来说,Profiler统计的内存较为一致,而Android系统通过ADB反馈的PSS、Private Dirty等值则是差别很大。这主要是因为芯片和OS的不同而导致。具体的Android内存,建议直接查看Google Android OS的相关文档。
Unity Profiler反馈的则是引擎的真实物理使用内存,一般我们都建议通过Profiler来查看内存是否存在冗余、泄露等问题。

16:已经预加载怪物,然后显示怪物 PSS上升,并且在隐藏怪物后并没有下降,这是什么原因导致?显存上去了吗?

仅仅隐藏怪物的话,内存是不会下降的。因为隐藏只是改变了GameObject的状态,并没有对内存中的Object和资源进行移除。同时,即使是提前加载了怪物,也依然可能存在以上问题,因为某些资源是在显示的时候,才会传输一份到GPU的,比如Mesh。一般情况下,显存都不会即刻降低,这个是由Graphics Driver来管理的。建议可以看Profiler是否增长,如果Profiler没有问题而PSS持续增长,就有可能发生了内存泄露。

对于这个问题,建议查看《性能优化,进无止境---内存篇(下)》加深理解。

17:对于Handheld.PlayFullScreenMovie 这个Unity播放开场动画的API,会有内存问题吗?比如我的mp4动画有20MB,那么这个动画会撑高mono堆内存吗?

Android上PlayFullScreenMovie 的实现实际上是通过Android原生的接口直接播放的,播放过程中Unity也是停止更新的,因此这部分的内存理论上并不会记录在 Unity 中,同样也不影响Mono。

18:Texture占用内存总是双倍,这个是我们自己的问题,还是Unity引擎的机制?

出现这种情况的原因有两种:一种是你在真机运行时开启了Read&Write。另一种可能是Unity的Bug,目前的Unity 5.2.3 release note如下 :
(735644) - OpenGL: Fixed texture memory usage reporting in profiler, was twice the actual size for most textures.
开发者需要关注下自己的开发版本,5.2.3以前类似情况的项目可以参考一下。

19:如果脚本引用了GameObject,那转换场景的时候脚本和GameObject都没了,还会产生堆内存的吗?

如果脚本是MonoBehaviour,而且在切换场景后所挂的Game Object被释放了,那么这个脚本对象所引用的堆内存就会在GC的时候被释放。 但有一种例外,如果是通过Static变量引用的堆内存,那么依然是释放不掉的,除非手动解开引用,比如变量置Null,数组Clear等等。

移动平台内存经验数据参考

Textures:80M-160M

Mesh:50M-70M

Render Textures:50M-80M

AnimationClips:30M-60M

Audio:10M-20M

Cubemap:0-50M

Font:5M-15M

Shader:20M-40M

System.xxx总和:15M-30M

AssetBundle:0-10M

其他各类对象单项:0-10M ,数量小于10000

ReservedMono:<100M

ReservedGFX:<300M

ReservedTotal:<650M

这些指标的上下限分别代表了在移动设备上的高低配数据的差异,其中Render Texture会根据目标设备的分辨率的不同会有差异变化。这里给出的是1080P分辨率下的经验数据指标。一些下限为零的指标为不使用此功能,可能没有这方面的开销数据,如果各个指标都在上述范围内,不优化也没有问题。

移动平台其他经验数据参考

DrawCall:300-600

SetPassCall:80-120

Triangles Count:60W-100W

Material Count:200-400

建议你的游戏相关指标也控制在此范围内,当然数据仅供参考。

在我的文章里你可能会看到重复的内容,原因是我的文章很多都是各路大神的心得,会有重复的,我没有删除,我觉得重复的多代表重要。

今天是2024年12月16日

重复一段毒鸡汤来勉励我和你

你的对手在看书

你的仇人在磨刀

你的闺蜜在减肥

隔壁的老王在练腰

而你在干嘛?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/938039.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

windows mysql5.7设置慢查询参数

如果没有my.ini,可以复制一份my-default.ini改个名字就可以。 注意重启mysql服务 mysql5.7 直接在配置文件my.ini 中写如下配置 log_slow_admin_statements ON log_slow_slave_statements ON slow_query_log 1 //开启慢查询 &#xff08;很多博客说on off ,我本机my…

STM32F407+LAN8720A +LWIP +FreeRTOS ping通

使用STM32CUBEIDE自带的 LWIP和FreeROTS 版本说明STM32CUBEIDE 操作如下1. 配置RCC/SYS2. 配置ETH/USART3. 配置EHT_RESET/LED4. 配置FreeRTOS5. 配置LWIP6. 配置时钟7. 生成单独的源文件和头文件,并生成代码8. printf重定义9. ethernetif.c添加lan8720a复位10. MY_LWIP_Init …

【电脑技巧】将键盘的方向键映射为alt+i、k、j、l

最近感觉方向键太远了&#xff0c;想找个方法修改键盘映射&#xff0c;有几种方式可以实现 使用powertoys的键盘映射&#xff08;软件太大了&#xff0c;只为键盘映射不值得下这个&#xff09;使用autohotkey&#xff08;通过脚本的方式&#xff0c;可以打包成exe文件&#xf…

物联网中的数据收集:MQTT实现的比较

本篇论文的标题是《Data collection in IoT: A comparison of MQTT implementations》&#xff0c;中文可以翻译为《物联网中的数据收集&#xff1a;MQTT实现的比较》。论文由Erik Gustafsson和Ruben Jarefors撰写&#xff0c;导师是Jalal Maleki&#xff0c;评审员是Rita Kovo…

【开源】使用环信UIKit for uniapp 做一个IM即时聊天应用

环信单群聊 UIKit 是基于环信即时通讯云 IM SDK 开发的一款即时通讯 UI 组件库&#xff0c;提供各种组件实现会话列表、聊天界面、联系人列表及后续界面等功能&#xff0c;帮助开发者根据实际业务需求快速搭建包含 UI 界面的即时通讯应用。 本文教大家使用环信 uniapp UIKit 快…

人工智能增强的音频和聊天协作服务

论文标题&#xff1a;AI-enabled Audio and Chat Collaboration Services 中文标题&#xff1a;人工智能增强的音频和聊天协作服务 作者信息&#xff1a; Emil P. Andersen, Norwegian Defence Research Establishment (FFI), Kjeller, NorwayJesper R. Goksr, Sindre E. Ha…

突破时间与空间限制的富媒体百宝箱——智能工具箱:让云上内容生产更easy

“这是你的同款日常吗&#xff1f;老是在赶deadline&#xff0c;苦练PS还未出师&#xff0c;premiere、达芬奇真的好难&#xff0c;学python脑容量确实不够~打工人太难了~~” 来试试智能工具箱吧&#xff01;即来即用&#xff0c;一键实现办公自由。图片工具、视频工具、音频工…

基于python绘制数据表(下)

绘制雷达图-源码 from openpyxl import Workbook from openpyxl.chart import RadarChart, Reference# 创建工作薄 wb Workbook() # 选定工作表 ws wb.active# 准备数据 rows [[Mouth, Bulbs, Seeds, Flowers, Trees],[Jan, 0, 2200, 500, 0],[Feb, 0, 2000, 560, 0],[Mar,…

PT2044A 单触控单输出IC

1 产品概述 ● PT2044A 是一款单通道触摸检测芯片。该芯片内建稳压电路&#xff0c;提供稳定电压给触摸感应电路使用。同时内部集成高效完善的触摸检测算法&#xff0c;使得芯片具有稳定的触摸检测效果。该芯片专为取代传统按键而设计&#xff0c;具有宽工作电压与低功耗的特性…

华为HarmonyOS实现跨多个子系统融合的场景化服务 -- 7 地图选点Button

场景介绍 本章节将向您介绍如何使用地图选点Button功能&#xff0c;开发者可调用Button组件拉起Map Kit的地图选点页面&#xff0c;用户在地图中选择位置后&#xff0c;位置相关信息返回Button界面。 说明 该场景暂不支持2in1设备。 前提条件 参见开发准备。 效果图展示 …

MVC流程分析

DisaptcherServlet本质是servlet&#xff0c;执行init()方法&#xff0c;自启动底层执行代码&#xff0c; 作用&#xff1a; 1、读取springmvc配置文件&#xff0c;创建Controller对象&#xff0c;放入容器中&#xff0c;map<"id",对象> 2、接收用户请求&#…

路径规划之启发式算法之十六:和声搜索算法(Harmony Search, HS)

和声搜索算法(Harmony Search, HS)是一种新兴的启发式全局搜索算法,是一种模拟音乐家即兴演奏过程的群体智能优化算法。这种算法由Zong Woo Geem等人在2001年提出,灵感来源于音乐家在寻找和声时的创造性思维过程。HS算法通过模拟音乐家演奏音乐时的选择过程来寻找问题的最优…

游戏引擎学习第45天

仓库: https://gitee.com/mrxiao_com/2d_game 回顾 我们刚刚开始研究运动方程&#xff0c;展示了如何处理当人物遇到障碍物时的情况。有一种版本是角色会从障碍物上反弹&#xff0c;而另一版本是角色会完全停下来。这种方式感觉不太自然&#xff0c;因为在游戏中&#xff0c;…

[2015~2024]SmartMediaKit音视频直播技术演进之路

技术背景 2015年&#xff0c;因应急指挥项目需求&#xff0c;我们实现了RTMP推送音视频采集推送&#xff08;采集摄像头和麦克风数据&#xff09;模块&#xff0c;在我们做好了RTMP推送模块后&#xff0c;苦于没有一个满足我们毫秒级延迟诉求的RTMP播放器&#xff0c;于是第一…

C语言实现八大排序算法

目录 1.插入排序 1.1 直接插入排序 1.2 希尔排序 2. 选择排序 2.1 直接选择排序 2.2 堆排序 *TopK问题&#xff1a; 3. 交换排序 3.1 冒泡排序 3.2 快速排序 1. Hoare版本 2. 挖坑法 3. 前后指针法 4. 快速排序优化 5. 非递归快速排序 4.归并排序 1.递归式归并…

走进 RAG 技术:一场智能数据交互的奇幻之旅

朋友们&#xff0c;咱身处的这个时代&#xff0c;科技那可是跟开了挂似的往前冲&#xff0c;其中人工智能更是厉害得没话说&#xff0c;宛如一个充满无限可能的魔法领域&#xff0c;时不时就给咱的生活来个大变样。而在这其中&#xff0c;RAG 技术就像是突然冒出来的一颗超亮眼…

商业化大前端在性能优化领域的探索与实践

导读&#xff1a;在业务飞速发展的过程中&#xff0c;用户体验是必不可少的一个环节&#xff0c;而页面性能是直接影响用户体验的重要因素。当页面加载时间过长、交互操作不流畅时&#xff0c;意味着业务可能会出现转化率降低、用户流失等业务问题。在过去一年&#xff0c;为了…

C# 位运算

一、数据大小对应关系 说明&#xff1a; 将一个数据每左移一位&#xff0c;相当于乘以2。因此&#xff0c;左移8位就是乘以2的8次方&#xff0c;即256。 二、转换 1、 10进制转2进制字符串 #region 10进制转2进制字符串int number1 10;string binary Convert.ToString(num…

YOLOv10改进,YOLOv10利用DLKAttention融合DCNv3、DCNv4形成全新的可变形大核注意力,并二次创新C2f结构,全网首发

理论介绍 完成本篇需要参考以下三篇文章,并已添加到YOLOv10代码中 YOLOv10改进,YOLOv10添加DCNv3可变性卷积与C2f结构融合(无需编译)YOLOv10改进,YOLOv10添加DCNv4可变性卷积(windows系统成功编译),全网最详细教程YOLOv10改进,YOLOv10添加DLKA-Attention可变形大核注意力…

Linux高性能服务器编程 | 读书笔记 | 8. 信号

8. 信号 信号是由用户、系统、进程发送给目标进程的信息&#xff0c;以通知目标进程某个状态的改变或系统异常。Linux信号可由以下条件产生&#xff1a; 对于前台进程&#xff0c;用户可通过输入特殊终端字符来给它发送信号&#xff0c;如输入CtrlC通常会给进程发送一个中断信…