Unity值类型和引用类型

我们都知道C#编程语言中,数据类型被分为了两种:

  1. 值类型
  2. 引用类型

那么什么是值类型?什么是引用类型呢?它们的区别又是什么?

为了搞清楚这些问题,我们先列举一下我们开发中会碰到的值类型和引用类型。

  • 常见的值类型为:byte,short,int,long,float,double,decimal,char,bool 和 struct
  • 常见的引用类型为:class array interface delegate string System.Object dynamic

为了更清晰的对比值类型和引用类型,我们从内存的分配和回收两个角度来进行分析

内存分配

我们都知道,创建对象就需要有一块内存来承载相应的对象,我们也知道,在程序运行过程中内存会分为栈内存和堆内存,那么到底我们的值类型和引用类型的内存是分配在哪块内存上了呢?
要搞清楚这个问题首先我们先要了解值类型和堆内存,内存分配的差异:

  • 值类型只需要一段单独的内存,用于存储实际的数据

  • 引用类型需要存储两段内存

    • 第一段存储实际的数据。
    • 第二段存储的是一个引用,指向实际数据的存放位置。

    其实很多熟悉开发的小伙伴都口熟能详的知道一个概念,“值类型被存储在内存栈上,引用类型被存储在内存堆上”。这句话对不对呢。继续往下看…
    其实这句话呢,也对也不对,但要分使用场景

    数据不是其它类型的成员的情况下“值类型被存储在内存栈上,引用类型被存储在内存堆上”,大致如下图所示:
    在这里插入图片描述

但我们实际开发中很多时候类型都不是单独存在的,看下面的一段代码:

  public class ClassA{public int a;public string b;}

看到代码是不是感觉 a内存分配在内存栈,b内存分配在内存堆。很遗憾,实际情况是a和b都被分配在内存堆中。

那么哪个环节出现问题了呢?
因为a是ClassA的成员属性,而ClassA是一个引用类型,所以ClassA的数据部分是被存储在内存堆上的,大致如下图所示:
在这里插入图片描述

总结:

引用类型的数据一定是被分配在内存堆上的,而引用类型的引用以及值类型的数据却并不一定分配在内存栈上。

  1. 局部变量:

引用类型的引用和值类型的数据分配在内存栈上

  1. 公共变量

引用类型的引用和值类型的数据的分配根承载它的对象所在的内存有关,如果承载它的对象在堆内存中那么它就跟着被分在堆内存中,如果承载它的对象被分配在栈内存中那么它就跟着被分在栈内存中。

内存回收

在说回收之前我们需要先了解一下栈内存和堆内存的定义和结构如下:

栈内存

栈是一个内存数组,是一个LIFO(last-in first-out,后进先出)的数据结构。栈存储几种类型的数据:某些类型变量的值、程序当前的执行环境、传递给方法的参数。

栈的特点:(1)数据只能从栈的顶端插入和删除。(2)把数据放到栈顶称为入栈。(3)从栈顶删除数据称为出栈。(4)内存连续 (5)内存自行维护

堆内存

堆是一块内存区域,在堆里可以分配大块的内存用于存储某种类型的数据对象。与栈不同,堆里的内存能够以任意顺序存入和移除。
堆的特点: (1)内存无序。 (2)内存不可自行维护需要借助CLR的GC机制

由于栈内存的内存连续性以及内存的自行维护,所以栈内存的申请和释放相对于堆内存要快。
而堆内存的内存回收完全借助于CLR的GC机制,什么时候回收几乎是不可控的,且由于堆内存的不连续性的特点,在GC之后容易产生内存碎片,从而造成内存浪费。

什么时候触发GC?

  1. 在堆内存上进行内存分配操作时,内存不够的时候会触发GC
  2. 自动触发,Unity会不定时的自动触发GC
  3. 代码强制执行

GC是怎样工作的?

  1. 挂起所有正在运行的线程
  2. 检查堆内存上的每个对象
  3. 搜索对象的所有引用
  4. 没有被引用的对象都是垃圾,被标记为可删除
  5. 遍历删除所有被标记的对象,释放内存

看到GC的工作机制你就会知道一次GC是多么的困难,并且随着我们的程序复杂性的提高,占用的CPU算力也会越高就会造成程序卡顿,所以在项目开发过程中我们一定要想办法减少GC,或选择在合适的位置进行GC

怎么减少GC?

  1. 对象池
  2. stringbuilder的使用
  3. 减少装箱操作
  4. 避免频繁的调用协程,每一次StartCoroutine()实际上是new一个新的对象
  5. 用for代替foreach foreach会在堆上产生一个system.object

最后我们简单用一个示例图来模拟一下一个引用类型的申请:

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【AI+老照片焕新】母亲节用AI把时间的印记变成暖心礼物

想念是一张泛黄的照片,藏在抽屉里的笑容,总是那么亲切。今天是母亲节,是不是想给妈妈来点不一样的惊喜?用AI技术,把那些老照片瞬间焕新,让妈妈的青春记忆重放光华! 想象一下,妈妈年…

使用Giskard进行LLM的测试

Giskard是一个对AI模型进行测试的平台,可以执行功能验证、安全测试及合规扫描。工具主要分为两大块:Giskard Python库和一个server端Giskard Hub。其中Python库是开源的,github地址:https://github.com/Giskard-AI/giskard 使用G…

(delphi11最新学习资料) Object Pascal 学习笔记---第11章第2节 (从接口引用中提取对象)

11.2.5 从接口引用中提取对象 ​ 在过去多个Object Pascal 语言版本中,当你将一个对象赋值给一个接口变量时,是无法访问原始对象的。有时,开发人员会在接口中添加一个 GetObject 方法来执行该操作,但这种设计非常奇怪。 ​ 在今…

华为校招机试 - 模拟汇编计算(20240508)

题目描述 要求设计一种虚拟机解释器,能解析并执行以下虚拟指令。 虚拟机约定: 32位的整型寄存器有 a0,a1,... ,a31 共 32 个寄存器整个虚拟机只有寄存器和立即数参与计算规则集: dst一定为寄存器src为寄存器或十进制正整数运算结果存在负数场景序号虚拟指令含义1MOV dst…

Unity读书系列《Unity高级编程:主程手记》——C#技术要点

文章目录 前言一、业务逻辑优化技巧二、Unity3d中C#的底层原理三、List底层源码剖析四、Dictionary底层源码剖析五、浮点数的精度问题六、委托、事件、装箱、拆箱七、算法总结 前言 本文旨在总结某一概念的性质,并引出相关的技术要点。如果读者希望深入了解相关技术…

docker部署调度程序

Dockerfile(构建初始镜像) # python:3.8-slim-buster为精简版的python FROM python:3.8-slim-buster # 1059为组的id,newgroup为组名,1088为用户的id,newuser为新用户 RUN groupadd -g 1059 newgroup && \useradd -g -u 1088 -g newgroup -m newuser USER newuser RUN…

Python函数和代码复用-课堂练习[python123题库]

函数和代码复用-课堂练习 1、来自计算机的问候-无参无返回值函数 类型:函数‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪…

react 屏幕信息滚动

1. 引入组件 import DoScrollingbar from @/components/basic/DoScrollingbar; 2.使用组件 <DoScrollingbar>{flightInfo.historytoday && flightInfo.historytoday.map(item => {return <div><div><span style={{ paddingRight: "10px&q…

如何根据招聘信息打造完美简历

如何根据招聘信息打造完美简历 招聘信息分析简历调整策略个性化与关键词结语 在求职过程中&#xff0c;简历是第一块敲门砖。它不仅展示了你的专业技能和工作经验&#xff0c;还体现了你对所申请职位的理解和热情。然而&#xff0c;如何从招聘信息中提炼关键点&#xff0c;打造…

如何在 Ubuntu 上创建一个 SSH CA 以验证主机和客户端

简介 在配置大量具有许多用户的服务器时&#xff0c;保持基础架构的 SSH 访问一致可能会变得复杂。有许多实现集中式身份验证机构的方法&#xff0c;例如 LDAP&#xff0c;但有时这些方法可能过于复杂。 SSH 实际上具有使用证书机构对服务器和客户端进行身份验证的功能。这种…

chatGLM或chatgpt:什么是tokens以及如何计算tokens长度?

token是什么? 简单的来说tokens就是大语言模型输入的向量数据,它是从原始的文本转化而来。 比如 输入:here is a text demo tokens为:[64790, 64792, 985, 323, 260, 2254, 16948] 解码:将tokens转化为文本 [‘[gMASK]’, ‘sop’, ‘▁here’, ‘▁is’, ‘▁a’, ‘▁…

mysql --- 内置函数

MySQL数据库提供了一系列内置函数&#xff0c;这些函数可以在SQL查询中使用&#xff0c;以执行计算、格式化数据、处理字符串、日期和时间等操作。这些函数可以大致分为几个类别&#xff1a;字符串函数、数值函数、日期和时间函数、控制流程函数、加密和压缩函数等。下面是一些…

神经网络模型与前向传播函数

1.概念 在神经网络中&#xff0c;模型和前向传播函数是紧密相关的概念。模型定义了网络的结构&#xff0c;而前向传播函数描述了数据通过网络的流动方式。以下是这两个概念的详细解释&#xff1a; 1.1 神经网络模型 神经网络模型是指构成神经网络的层、权重、偏置和连接的集…

SpringBoot拦截器中使用RedisTemplate

这几天想着把登陆拦截器的验证规则修改一下&#xff0c;验证介质由session中获取改为从redis中获取&#xff0c;结果发现redisTemplate一直为空&#xff0c; Configuration public class WebInterceptorConfig implements WebMvcConfigurer {Overridepublic void addIntercept…

源码知识付费系统,在线教学平台需要优化什么?

在线教育关于广大的关注者而言属于快捷度非常高的传达途径&#xff0c;尤其是白日没有过多时间的上班族或学习繁忙的学生&#xff0c;均能够通过可靠的在线教育完结自己的目的。如此巨大的市场潜力使得以在线教育为主的公司数量呈现出直线上升的趋势&#xff0c;很多的在线教育…

零基础掌握Kafka

Apache Kafka是当前最流行的分布式流处理平台之一&#xff0c;由LinkedIn开发并于2011年开源。它被设计用于高吞吐量、低延迟的场景&#xff0c;广泛应用于日志收集、流处理、事件源等多种场合。本文将带你从零开始学习Kafka&#xff0c;并通过Java代码示例展示如何发送消息。 …

scrapy的入门

今天我们先学习一下scrapy的入门,Scrapy是一个快速的高层次的网页爬取和网页抓取框架&#xff0c;用于爬取网站并从页面中提取结构化的数据。 1. scrapy的概念和流程 1.1 scrapy的概念 我们先来了解一下scrapy的概念,什么是scrapy: Scrapy是一个Python编写的开源网络爬虫框架…

AI学习指南概率论篇-贝叶斯推断

AI学习指南概率论篇-贝叶斯推断 概述 在人工智能中&#xff0c;贝叶斯推断是一种基于贝叶斯统计理论的推理方法。它通过使用概率论的知识&#xff0c;结合先验信息和观测数据&#xff0c;来更新对未知变量的推断。贝叶斯推断提供了一种合理的方法来处理不确定性&#xff0c;并…

ubuntu 相关操作

ubunt-desktop卸载重安 sudo apt-get purge ^gnome-.* sudo apt-get autoremove --purge sudo apt-get update sudo apt-get install ubuntu-desktop清理 # 检查日志大小 journalctl --disk-usage# 只保留一周的日志 sudo journalctl --vacuum-time1w# 只保留500MB的日志 …

JS遍历数组的十种方法总结

​​​ 目录 一、for 循环遍历 二、for ... of 方法 三、for...in循环 四、forEach 遍历 五、map 映射 六、filter方法 七、reduce高阶函数&#xff08;迭代&#xff08;累加器&#xff09;&#xff09; 八、every 九、some 十、find 一、for 循环遍历 for循环是最…