官术网_书友最值得收藏!

Avoid retrieving string properties from GameObjects

Ordinarily, retrieving a string property from an object is the same as retrieving any other reference type property in C#; it should be acquired with no additional memory cost. However, retrieving string properties from GameObjects is another subtle way of accidentally crossing over the Native-Managed Bridge.

The two properties of GameObject affected by this behavior are tag and name. Therefore, it is unwise to use either property during gameplay, and you should only use them in performance-inconsequential areas, such as editor scripts. However, the tag system is commonly used for the runtime identification of objects, which can make this a significant problem for some teams.

For example, the following code would cause an additional memory allocation during every iteration of the loop:

for (int i = 0; i < listOfObjects.Count; ++i) {
if (listOfObjects[i].tag == "Player") {
// do something with this object
}
}

It is often a better practice to identify objects by their components and class types and to identify values that do not involve string objects, but sometimes we're forced into a corner. Maybe we didn't know any better when we started, we inherited someone else's code base, or we're using it as a workaround for something. Let's assume that, for whatever reason, we're stuck with the tag system, and we want to avoid the Native-Managed Bridge overhead cost.

Fortunately, the tag property is most often used in comparison situations, and GameObject provides the CompareTag() method, which is an alternative way to compare tag properties that avoids the Native-Managed Bridge entirely.

Let's perform a simple test to prove how this simple change can make all the difference:

void Update() {

int numTests = 10000000;

if (Input.GetKeyDown(KeyCode.Alpha1)) {
for(int i = 0; i < numTests; ++i) {
if (gameObject.tag == "Player") {
// do stuff
}
}
}

if (Input.GetKeyDown(KeyCode.Alpha2)) {
for(int i = 0; i < numTests; ++i) {
if (gameObject.CompareTag ("Player")) {
// do stuff
}
}
}
}

We can execute these tests by pressing the 1 and 2 keys to trigger the respective for loops. Here are the results:

Looking at the breakdown view for each spike, we can see two completely different outcomes:

It's worth noting how the two spikes in the Timeline View appear relatively the same height, and yet one operation took twice as long as the other. The Profiler doesn't have the vertical resolution necessary to generate relatively accurate peaks when we go beyond the 15FPS marker. Both would result in a poor gameplay experience anyway, so the accuracy doesn't really matter.

Retrieving the tag property 10 million times (way more than makes sense in reality, but this is useful for comparison) results in about 400 megabytes of memory being allocated just for string objects alone. We can see this memory allocation happening in the spike within the GC Allocated element in the Memory Area of the Timeline View. Also, this process takes around 2,000 milliseconds to process, where another 400 milliseconds are spent on garbage collection once the string objects are no longer needed.

Meanwhile, using CompareTag() 10 million times costs around 1,000 milliseconds to process and causes no memory allocations, and hence no garbage collection. This is made apparent from the lack of a spike in the GC Allocated element in the Memory Area. This should make it abundantly clear that we must avoid accessing the name and tag properties whenever possible. If tag comparison becomes necessary, then we should make use of CompareTag(). Unfortunately, there is no equivalent for the name property, so we should stick to using tags where possible.

Note that passing in a string literal, such as  "Player", into CompareTag() does not result in a runtime memory allocation since the application allocates hardcoded strings like this during initialization and merely references them at runtime.
主站蜘蛛池模板: 昭平县| 通许县| 宣威市| 临海市| 汉寿县| 达州市| 金昌市| 内丘县| 乡宁县| 屯门区| 福海县| 南充市| 专栏| 盐津县| 璧山县| 广饶县| 馆陶县| 重庆市| 石门县| 铜川市| 金秀| 十堰市| 龙江县| 台北市| 彭泽县| 嘉峪关市| 石城县| 西充县| 巴马| 淮安市| 万源市| 宝鸡市| 昌吉市| 康平县| 墨脱县| 抚宁县| 集安市| 招远市| 余江县| 古交市| 海宁市|