unityprofiler
2020-03-30 14:49 kk20161206 阅读(213) 评论(0) 收藏 举报unity优化之profile数据:https://www.muchenhen.com/2019/03/21/%E3%80%90unity%E4%BC%98%E5%8C%96%E3%80%91profiler%E6%80%A7%E8%83%BD%E5%88%86%E6%9E%90%E5%99%A8/
Unity内存管理机制
(1)堆内存和堆栈内存两种内存管理池,堆栈存较小和短暂的数据,堆存较大、存储时间较长的数据。
(2)unity中的变量只会在堆栈或者堆内存上进行内存分配
(3)只要变量处于激活状态,则其占用的内存会被标记为使用状态,则该部分的内存处于被分配的状态
(4)一旦变量不再激活,则其所占用的内存不再需要,该部分内存可以被回收到内存池中再次被使用,这样的操作就是内存回收。处于堆栈上的内存回收速度极其快速,处于堆上的内存并不是及时回收的,因此其对应的内存依然会被标记为使用状态。
(5)垃圾回收主要是指堆上的内存分配和回收,unity中会定时堆堆内存进行GC操作
堆栈上的内存分配和回收十分快捷简单,因为堆栈上只会存储短暂的或者较小的变量。内存分配和回收都会一种顺序和大小都可控制的形式进行。 堆栈的运行方式就像数据结构的stack一样,本着先进后出的原则
(1)首先,unity检测是否有足够的闲置内存单元用来存储数据,如果有,则分配对应大小的内存单元;
(2)如果没有足够的内存单元,unity会触发来及回收来释放不再被使用的堆内存。这步操作是一步缓慢的操作,如果垃圾回收后有足够大小的内存单元则进行内存分配;
(3)如果垃圾回收后并没有足够的内存单元,则unity会扩展堆内存的大小,这种操作会很缓慢,然后分配对应大小的内存单元给变量;
(1)GC会检查堆内存上的每个存储变量; (2)对每个变量会检测其引用是否处于激活状态; (3)如果变量的引用不再处于激活状态,则会被标记为可回收; (4)被标记的变量会被移除,其所占有的内存会被回收给堆内存。
主要有三个操作会触发垃圾回收: (1)在堆内存上进行内存分配操作而内存不够的时候; (2)GC会自动的触发,不同的平台运行频率不一样; (3)GC可以被强制执行。
void ExampleFunc()
{
int localInt =5;
}
void ExampleFunc()
{
List localList = new List();
}
(1)减少GC运行的次数; (2)减少单次GC的运行时间; (3)将GC的运行时间延迟,避免在关键时刻触发,如在加载场景是调用GC
(1)对游戏进行重构,减少堆内存的分配和引用的分配。
更少的变量和引用会减少GC操作中的检测个数
从而提高GC运行的效率
(2)降低堆内存分配和回收的频率,尤其是在关键时刻。
也就是说更少的事件触发GC操作,同时也降低堆内存的碎片化
(3)我们可以试着测量GC和堆内存扩展的时间,使其按照可预测的顺序执行。
当然这样操作的难度极大,但是这会大大降低GC的影响
void OnTriggerEnter(Collider other)
{
Renderer[] allRenderers = FindObjectsOfType<Renderer>();
ExampleFunction(allRenderers);
}
private Renderer[] allRenderers;
void Start()
{
allRenderers = FindObjectsOfType<Renderer>();
}
void OnTriggerEnter(Collider other)
{
ExampleFunction(allRenderers);
}
private float timeSinceLastCalled;
private float interval;
void Update()
{
timeSinceLastCalled +=Time.deltaTime;
if(timeSinceLastCalled>interval)
{
ExampleGarbageGenerationFunction();
timeSinceLastCalled = 0f;
}
}
void Update()
{
List myList = new List();
PopulateList(myList);
}
private List myList = new List();
void Update()
{
myList.Clear();
PopulateList(myList);
}
public Text timerTxt;
private float timer;
void Update()
{
timer +=Time.deltaTime;
timerTxt.text = "Time:" + timer.ToString();
}
public Text timerHeaderTxt;
public Text timerValueTxt;
private float timer;
void Start()
{
timerHeaderText.text = "TIME:";
}
void Update()
{
timerValueTxt.text = timer.ToString();
}
void ExampleFunction()
{
for(int i=0;i<myMesh.normals.Length;i++)
{
Vector3 normal = myMesh.normals[i];
}
}
void ExampleFunction()
{
Vector3[] meshNormals = myMesh.normals;
for(int i =0;i<meshNormals.Length;i++)
{
Vector3 normal = meshNormals[i];
}
}
private string playerTag = "Player";
void OnTriggerEnter(Collider other)
{
bool isPlayer = other.gameObject.tag == playerTag;
}
private string playerTag = "Player";
void OnTriggerEnter(Collider other)
{
bool isPlayer = other.gameObject.Compare(playerTag);
}
void ExampleFunction()
{
int cost = 5;
string displayString = Srting.Format("Price:{0} glod",cost);
}
yield return 0;
yield return null;
while(!complete)
{
yield return new WaitForSeconds(1f);
}
WaitForSeconds delay = new WaitForSeconds(1f);
while(!insComplete)
{
yield return delay;
}
void ExampleFunction(List listOfInts)
{
foreach(int currentInt in listOfInts)
{
DoSomething(currentInt);
}
}
void ExampleFunction(List listOfInts)
{
for(int i = 0;i< listOfInts.Count;i++)
{
int currentIn = listOfInts[i];
DoSometing(currentInt);
}
}
public struct ItemData
{
public string name;
public int cost;
public Vector3 position;
}
private ItemData[] itemData;
private string[] itemNames; private int[] itemCosts; private Vector3[] itemPositions;
public class DialogData
{
private DialogData nextDialog;
public DialogData GetNextDialog()
{
return nextDialog;
}
}
public class DialogData
{
private int nextDialogID;
public int GetNextDialogID()
{
return nextDialogID;
}
}
System.GC.Collect()
10. 枚举和字典
Dictionary.add(key, value) 会调用 Object.getHashCode(Object),Object.getHashCode是引用类型,enum是值类型,以enum为key的字典会导致装箱操作。所以,最好实现个IEqualityComparer接口,该接口的实现传给dictionary的构造函数,dictionary的比较。
public class MyEnumComparer : IEqualityComparer<MyEnum> {
public bool Equals(MyEnum x, MyEnum y) {
return x == y;
}
public int GetHashCode(MyEnum x) {
return (int)x;
}
}
11. Empty array reuse
Some teams prefer to return empty arrays instead of null when an array-valued method needs to return an empty set. This coding pattern is common in many managed languages, particularly C# and Java.
In general, when returning a zero-length array from a method, it is considerably more efficient to return a pre-allocated singleton instance of the zero-length array than to repeatedly create empty arrays(5) (Note: Naturally, an exception should be made when the array is resized after being returned)
12. string的优化:
String.Equals("encyclopedia", “encyclopædia”); myString.Equals(otherString, StringComparison.Ordinal);
Inefficient built-in string APIs
String.StartsWith and String.EndsWith can be replaced with simple hand-coded versions
Regular Expressions
Regex.Match(myString, "foo");
改为:
var myRegExp = new Regex("foo"); myRegExp.Match(myString);
unity允许自己的引擎代码和我们的脚本代码方式不同。他自己的引擎代码用手动内存管理进行管理。核心引擎代码要显示写内存怎么用。手动内存管理不用gc。
允许我们的代码用自动内存管理。
自动内存管理: 堆栈,堆(托管堆),短期、长期数据。
https://gameinstitute.qq.com/community/detail/125200
https://docs.unity3d.com/Manual/BestPracticeUnderstandingPerformanceInUnity4-1.html
https://docs.unity3d.com/Manual/BestPracticeUnderstandingPerformanceInUnity5.html
https://learn.unity.com/tutorial/fixing-performance-problems#5c7f8528edbc2a002053b595
浙公网安备 33010602011771号