游戏引擎学习第14天

1. 为什么关注内存管理?

  • 内存分配是潜在的失败点

    • 每次进行内存分配(mallocnew等)时,都可能失败(例如内存不足)。
    • 这种失败会引入不稳定性或不可预测性,需要额外的错误处理逻辑。
  • 传统编程的理念

    • 在“老派编程”中,作者更倾向于避免动态内存分配,通过静态或固定大小的缓冲区管理内存,从而使程序更加稳定和可靠。

2. 如何避免动态内存分配?

  • 示例中使用的策略
    • 程序需要两个缓冲区(一个音频缓冲区和一个位图缓冲区),它们通过操作系统一次性分配完成,且在整个程序生命周期内从不释放(never freed)。
    • 这种设计消除了动态内存分配的风险,也避免了与内存回收(如垃圾回收)相关的复杂性。

3. 动态内存分配的挑战

  • 现代编程环境的现状

    • 现代程序大量依赖动态内存分配和垃圾回收(如Java、C#中的GC机制)。
    • 动态内存管理可能导致性能抖动(如虚拟内存分页),难以预测程序的行为。
  • 作者的观点

    • 过多依赖动态内存分配,使得程序开发变得复杂且不可控。
    • 作者更喜欢“静态内存分配”或“固定缓冲区”的方法,使程序从一开始就处于稳定状态。

4. 静态内存管理的优点

  • 高可靠性

    • 程序一旦启动,就不会因为内存问题而失败。
  • 简单性

    • 减少内存泄漏和回收相关的复杂性。
  • 性能一致性

    • 消除了垃圾回收或虚拟内存分页带来的性能抖动。

5. 哲学层面的思考

  • 作者更喜欢探索传统编程中的一些“简单且有趣”的做法,比如尽可能避免动态内存分配。
  • 他认为,这种方法可以让编程回归本质——精心设计和实现代码,而不是依赖现代编程环境中的各种工具和机制。

这段视频主要在讨论内存分配的优化以及游戏开发中不同的设计思路。以下是对这段对话的简要总结:

  1. 内存分配策略

    • 演讲者建议采用预分配内存的方式,而不是在运行时频繁分配。
    • 他提到这种方法类似“旧学校”的平分区策略,即一开始抓取一块大内存,并为每个子系统预先分配固定的空间。
  2. 静态变量的使用

    • 演讲者提到使用 static 定义的“局部持久变量”,它本质上是一种作用域限制在函数内的全局变量。
    • 他不喜欢这种设计,因为它可能导致代码混乱和难以维护。
  3. 传统与现代的差异

    • 他对比了旧式街机程序员的开发风格和现代普遍的“内存分配狂欢”方法。
    • 强调大多数现代游戏不会采用他的方式,但他认为提供不同的视角是有意义的。
  4. 未来设计计划

    • 他计划展示如何将游戏状态存储在预先分配的内存中。
    • 演讲者希望避免动态分配,并使用更高效的方式管理内存。
  5. 强调多样化的视角

    • 演讲者明确指出,他并不是在提倡大家完全采用他的方式,而是提供一种不同的思考方式。

这种方法对某些嵌入式系统或资源受限的环境可能很有帮助,但在资源丰富的现代系统中可能并不常见。您对这段内容是否还有特定部分需要进一步解析?

在某些编程或系统设计情况下,处理失败案例的挑战,特别是与内存分配相关的挑战。

  1. 失败案例的策略

    • 必须有一个处理失败案例的计划。例如,每当进行新的资源分配时,需要检查分配是否成功,并妥善处理可能的失败情况。这可能需要复杂的逻辑来处理多种路径的成功或失败。
  2. 现实中的折中策略

    • 一种方法是通过测试运行系统,观察其内存使用情况,并确保启动时分配足够的内存。
    • 使用自定义分配器,预先分配一定的内存以避免运行中内存不足,但这种方法依赖于测试的全面性。
  3. 未知风险的接受

    • 有时,只能假设程序不会超出所需的内存范围,希望玩家或用户不会触发未考虑到的极端场景。这种方法依赖于假设和希望,而不是完全可靠的保障。
  4. 故事的必要性

    • 在设计系统时,需要为失败场景找到一个“故事”或策略,即使有时故事仅仅是“不清楚,但在测试中未发现问题”。
  5. 个人观点

    • 作者对这些策略并不满意,认为这些都不是理想的答案,但在实践中可能不得不接受其中之一。

平台抽象设计中关于游戏与平台之间交互的复杂性,以及如何简化这种交互。以下是总结:

  1. 循环调用的缺点

    • 游戏和平台之间频繁的双向调用(循环调用)会增加复杂性,使得理解两者之间的关联变得更加困难。
    • 这种复杂性在高级功能(如记录和回放整个游戏会话以进行调试)中尤为明显。
  2. 推荐的设计方式

    • 建议设计为简单的数据流模式:
      • 平台作为服务请求游戏提供必要的数据(如视频帧、音频输出等)。
      • 输入(如用户操作)直接传递到游戏,输出直接返回到平台。
    • 避免游戏层再调用平台,这种方式可以减少系统的耦合性,简化回放系统的实现。
  3. 单线程时代的优势

    • 在过去的单线程环境中,这种输入流和输出流定义明确的设计简化了调试工作(例如回放游戏的整个会话)。
    • 单一输入和输出流的模型使得系统在逻辑上更容易追踪和复现问题。
  4. 多核时代的挑战

    • 如今由于多核架构的普及,线程化操作增加了复杂性,使回放系统变得困难。
    • 线程化问题导致这种设计在现代环境中不再像过去那样具有优势。
  5. 结论

    • 过去单线程的设计逻辑有其历史意义和现实效率,但在现代多线程环境中,需要权衡线程管理的难度和系统简单性之间的关系。

游戏开发中的内存管理哲学进行了讨论。以下是要点总结:

  1. 内存管理的责任分配

    • 平台层在游戏启动时分配一块大内存给游戏。
    • 游戏负责对这块内存进行进一步分区和管理。
    • 游戏内的所有系统都必须在一个固定的内存空间中操作,确保游戏启动后能够运行至结束而不会因内存问题失败。
  2. 可靠性目标

    • 游戏开发的目标是做到“一旦启动,就不会失败”。
    • 即使某些资源(如精灵)丢失,游戏仍然能够正常运行。
    • 平台层可能会由于操作系统的问题而失败(例如 Windows 的设计缺陷),但这不会影响游戏的整体可靠性。
  3. 资源管理的哲学

    • 开发中采用“零失败状态”原则,即尽量减少游戏运行中的错误。
    • 提议了“金银铜”标准,以根据不同游戏的复杂程度评估其达到可靠性目标的水平。
  4. 延伸到磁盘 I/O

    • 与内存管理类似,对磁盘 I/O 的管理也遵循相同的哲学,以尽量减少失败。

作者表示,动态分配本质上是一种"自欺欺人"的做法,因为它假设内存是无限的,而实际上硬件的内存是有限的。如果不控制内存使用,程序可能会在运行时遇到不可预见的问题,如内存不足或碎片化。
采用主存池的方案,可以保证程序在固定内存下运行,减少风险。尤其是在面向最终用户的产品中,确保内存不会超出限制并且程序能顺利启动和运行是非常重要的。
1:03:31Why use the void* in game_memory?
在这段字幕中,主要的内容涉及内存管理和如何在游戏中处理不确定类型的内存块。可以从中提取出以下几个关键点:

  1. 不确定的内存块:由于游戏内存的某些部分是不确定的,我们不能为这些部分指定类型。这些部分被视为一个“大内存块”,游戏可以根据需要任意处理这些内存数据。

  2. void指针:提到使用空指针(或void指针)来指示这些不确定的内存块。因为我们不知道它们的具体类型,所以使用void指针来管理这些内存是一个常见的做法。

  3. 类型转换:虽然开始时内存块没有明确的类型,但可以在后续转换成具体的游戏状态或其他类型,并开始进行类型化管理。

  4. 游戏中的使用:游戏开发中常常需要处理各种类型的内存,这些内存数据可以根据需求灵活地操作和转换成具体的类型。

  5. “冷启动”和“冷转换”:提到的“冷启动”和“冷转换”暗示着这些内存块被快速转换成所需的格式,过程没有太多的复杂操作,直接转换为游戏所需要的状态。

  6. 游戏规模的影响:由于游戏的规模可能很大,这种内存处理方法显得尤为重要,能够动态地应对不同类型的内存需求。

存储管理和游戏开发中的一些技术概念。可以理解为以下几点:

  1. 永久存储和临时存储的区分

    • 永久存储:指的是游戏在运行过程中必须保持的数据,这些数据对游戏的持续运行至关重要,例如玩家的进度、已解锁的内容等。
    • 临时存储:是一些临时存储的数据,可以在不影响游戏运行的情况下清除或重新加载,例如缓存的纹理、声音等资源。
  2. 区分的原因

    • 性能优化:临时存储的数据可以被刷新(如在游戏运行时清空缓存),这有助于优化性能,减少内存占用。比如,在iPhone等设备上,清空缓存有助于减少应用的内存占用。
    • 事件驱动:临时存储的数据可能会受到某些事件的影响(例如用户的操作或系统事件),而这些数据不一定需要长期保存。
  3. 为什么分开处理

    • 这样做是为了能够对数据进行更灵活的管理,例如在需要时清除临时存储的数据,而不会影响到永久存储中的重要数据。
    • 这种区分还有助于一些额外的优化技巧,例如缓存和重新加载过程的优化。
  4. 后期调整

    • 在开发过程中,可能会根据实际需求调整永久和临时存储的具体实现,这种调整是灵活的,因此开发者可能会先写好代码框架,再根据实际情况做修改。

避免在平台层和游戏层之间进行频繁往返调用(即“往返旅行”),这种设计模式可能导致系统中的复杂性和性能问题。以下是一个简要的总结:

  1. 避免内存分配的往返:谈话的重点之一是避免频繁在平台层和游戏之间进行内存分配的往返。这种“往返旅行”指的是平台层调用游戏层,游戏层再调用回平台层,从而引入不必要的复杂性和性能开销。

  2. 虚拟化的例子:提到一个虚拟化的例子,试图通过设计避免频繁的内存分配和平台调用之间的交互,这样可以减少系统中的“蜘蛛网”式的复杂关系。

  3. 堆栈和调用关系:系统中创建了一个堆栈,其中平台层和游戏层交替调用,这种结构可能导致管理上的困难,尤其是当每个组件由不同的开发人员编写时。

  4. 简化设计:最后提到的优化建议是,如果设计得当(比如通过传递合适的参数),可以简化整个调用结构,使得系统运行更加高效且易于维护。

总的来说,这段对话强调了通过避免复杂的相互依赖关系和频繁的内存分配,可以让系统变得更高效、更简洁。

下面是平台独立内存代码的修改

在这里插入图片描述

任务管理器查看内存提交的大小

在这里插入图片描述

vscode 的一个小插件

在这里插入图片描述

    "workbench.colorCustomizations": {
        // 新增文本的背景颜色
        "diffEditor.insertedTextBackground": "#00501388", // 浅绿色,带透明度
        // 删除文本的背景颜色
        "diffEditor.removedTextBackground": "#62000088", // 浅红色,带透明度
        // 修改区域的边框颜色(可选)
    },

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

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

相关文章

QT6学习第一天

QT6安装和示例运行 QT介绍QT特点QT开发框架QT Quick和QML介绍Qt Widgets和Qt QuickQT6下载安装QT Creator介绍QT Creator界面介绍 QT介绍 Qt是一个跨平台的应用程序和UI开发框架,可用于桌面、嵌入式和移动平台的应用程序和用户界面的开发。 使用Qt只需一次性开发应…

一文详细深入总结服务器选型

1. 题记: 服务器选型工作是项目规划检讨的一项非常重要的工作,本文详细深入总结服务器选型。 2. 服务器基础知识概览 2.1 服务器的定义与功能 2.1 .1 定义 服务器是一种高性能计算机,其设计目的是在网络中提供服务。它可以处理来自多个客…

打造旅游卡服务新标杆:构建SOP框架与智能知识库应用

随着旅游业的蓬勃兴起,旅游卡产品正逐渐成为市场的焦点。为了进一步提升服务质量和客户体验,构建一套高效且标准化的操作流程(SOP)变得尤为重要。本文将深入探讨如何构建旅游卡的SOP框架,并介绍如何利用智能知识库技术…

基于Python爬虫大屏可视化的热门旅游景点数据分析系统

作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏:…

04 - Clickhouse-21.7.3.14-2单机版安装

目录 一、准备工作 1、确定防火墙处于关闭状态 2、CentOS 取消打开文件数限制 3、安装依赖 4、CentOS取消SELINUX 二、单机安装 2.1、下载安装 2.2、安装这4个rpm包 2.3、修改配置文件 2.4、启动服务 2.5、关闭开机自启 2.6、使用Client连接server 一、准备工作 1…

uni-app移动端与PC端兼容预览PDF文件

过程遇到的问题 1、如果用的是最新的版本的pdfjs的话,就会报Promise.withResolvers 不是一个方法的错误,原因是Promise.withResolvers是ES15新特性,想了解可参考链接,这里的解决方案是将插件里的涉及到Promise.withResolvers的地…

shell编程--永久环境变量和字符串显位

环境变量 echo $HOME 在终端输出后会显示家目录有个root变量 我们会提出个疑问为什么平时我们在终端输入sl 或者which等等命令会输出一些内容呢,这是因为这些命令都有对应的环境变量。 我们查看一下环境变量 在终端输入: echo $PATH 我们看一下输出…

vue3 + vite 进行axios请求封装及接口API的统一管理

前言 在Vue 3项目中使用Vite进行开发时,对axios进行请求封装以及统一管理接口API是非常常见的做法。这不仅可以提高代码的复用性和可维护性,还能统一处理请求和响应,管理错误处理逻辑等。下面是一个详细的步骤和示例代码,来说明如…

十三、注解配置SpringMVC

文章目录 1. 创建初始化类,代替web.xml2. 创建SpringConfig配置类,代替spring的配置文件3. 创建WebConfig配置类,代替SpringMVC的配置文件4. 测试功能 1. 创建初始化类,代替web.xml 2. 创建SpringConfig配置类,代替spr…

关于win11电脑连接wifi的同时,开启热点供其它设备连接

背景: 我想要捕获手机流量,需要让手机连接上电脑的热点。那么问题来了,我是笔记本电脑,只能连接wifi上网,此时我的笔记本电脑还能开启热点供手机连接吗?可以。 上述内容,涉及到3台设备&#x…

【OpenGL】OpenGL简介

文章目录 OpenGL概述OpenGL的本质OpenGL相关库核心库窗口管理glutfreeglutglfw 函数加载glewGLAD OpenGL概述 OpenGL(Open Graphics Library) 严格来说,本身并不是一个API,它是一个由Khronos组织制定并维护的规范(Specification)。OpenGL规范严格规定了…

AI写作(十)发展趋势与展望(10/10)

一、AI 写作的崛起之势 在当今科技飞速发展的时代,AI 写作如同一颗耀眼的新星,迅速崛起并在多个领域展现出强大的力量。 随着人工智能技术的不断进步,AI 写作在内容创作领域发挥着越来越重要的作用。据统计,目前已有众多企业开始…

ROS进阶:使用URDF和Xacro构建差速轮式机器人模型

前言 本篇文章介绍的是ROS高效进阶内容,使用URDF 语言(xml格式)做一个差速轮式机器人模型,并使用URDF的增强版xacro,对机器人模型文件进行二次优化。 差速轮式机器人:两轮差速底盘由两个动力轮位于底盘左…

Java 网络编程(二)—— TCP流套接字编程

TCP 和 UDP 的区别 在传输层,TCP 协议是有连接的,可靠传输,面向字节流,全双工 而UDP 协议是无连接的,不可靠传输,面向数据报,全双工 有连接和无连接的区别是在进行网络通信的时候,…

YOLOv8改进,YOLOv8通过RFAConv卷积创新空间注意力和标准卷积,包括RFCAConv, RFCBAMConv,二次创新C2f结构,助力涨点

摘要 空间注意力已广泛应用于提升卷积神经网络(CNN)的性能,但它存在一定的局限性。作者提出了一个新的视角,认为空间注意力机制本质上解决了卷积核参数共享的问题。然而,空间注意力生成的注意力图信息对于大尺寸卷积核来说是不足够的。因此,提出了一种新型的注意力机制—…

Python调用API翻译Excel中的英语句子并回填数据

一、问题描述 最近遇到一个把Excel表中两列单元格中的文本读取,然后翻译,再重新回填到单元格中的案例。大约有700多行,1400多个句子,一个个手动复制粘贴要花费不少时间,而且极易出错。这时,我们就可以请出…

虚拟化数据恢复—ESX SERVER共享的STORAGE中分区表被清零的数据恢复案例

虚拟化数据恢复环境&故障: 某单位信息管理平台,数台VMware ESX SERVER共享一台某品牌DS4100存储。 vc报告虚拟磁盘丢失,管理员ssh到ESX中执行fdisk -l查看磁盘,发现STORAGE中的分区表不见了。重启所有设备后,ESX S…

无效的目标发行版17和无法连接Maven进程问题

起因:我clean了一个模块的Maven想要重新下,他就开始报错。两次了都是这样。如果和我一样一开始都是好好的,直接找Maven的设置,在运行程序改,jre变成了11.它自己变成了我其他的jdk

在Docker环境下为Nginx配置HTTPS

前言 配置HTTPS已经成为网站部署的必要步骤。本教程将详细介绍如何在Docker环境下为Nginx配置HTTPS,使用自签名证书来实现加密通信。虽然在生产环境中建议使用权威CA机构颁发的证书,但在开发测试或内网环境中,自签名证书是一个很好的选择。 …

英伟达基于Mistral 7B开发新一代Embedding模型——NV-Embed-v2

我们介绍的 NV-Embed-v2 是一种通用嵌入模型,它在大规模文本嵌入基准(MTEB 基准)(截至 2024 年 8 月 30 日)的 56 项文本嵌入任务中以 72.31 的高分排名第一。此外,它还在检索子类别中排名第一(…