問題發(fā)現(xiàn):當(dāng)在Upade中使用倒計(jì)時(shí)的時(shí)候,會(huì)出現(xiàn)大量的內(nèi)存分配,這個(gè)內(nèi)存分配主要是tostring()或string.format引起的,這就導(dǎo)致了頻繁的GC。
1. 先看4種狀態(tài)下的獲取string的內(nèi)存比較(int.tostring(),SpeedString,char.tostring,StringBuilder.Tostring())
代碼如下:
public void Update()
{
IntTostring();
StringBuilderTostring();
CharsTostring();
SpeedStringToString();
}
System.Text.StringBuilder builder = new System.Text.StringBuilder(50);
private void IntTostring(int time = 10000)
{
string timeStr = time.ToString();
}
private void StringBuilderTostring(int time =1)
{
builder.Length = 0;
builder.Append("1000");
string timeStr = builder.ToString();
}
private void CharsTostring(int time = 1)
{
chars[0] = (char)(time + '0');
chars[1] = (char)(time + '0');
chars[2] = (char)(time + '0');
string timeStr = chars.ToString();
}
int i =10000;
private void SpeedStringToString()
{
speedStr.Clear();
speedStr.Append(Random.Range(0,100000));
string str = speedStr.string_base;
}
SpeedString speedStr = new SpeedString(10);
char[] chars = new char[4];
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
SpeedString的實(shí)現(xiàn)(參考http://forum./threads/stringbuilder-problem.122262/)
public class SpeedString
{
public string string_base;
public System.Text.StringBuilder string_builder;
private char[] int_parser = new char[11];
public SpeedString(int capacity)
{
string_builder = new System.Text.StringBuilder(capacity, capacity);
string_base = (string)string_builder.GetType().GetField(
"_str",
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance).GetValue(string_builder);
}
private int i;
public void Clear()
{
string_builder.Length = 0;
for (i = 0; i < string_builder.Capacity; i++)
{
string_builder.Append(' ');
}
string_builder.Length = 0;
}
//public void Draw(ref string text){
// text.text = "";
// text.text = string_base;
// text.cachedTextGenerator.Invalidate();
//}
public void Append(string value)
{
string_builder.Append(value);
}
int count;
public void Append(int value)
{
if (value >= 0)
{
count = ToCharArray((uint)value, int_parser, 0);
}
else
{
int_parser[0] = '-';
count = ToCharArray((uint)-value, int_parser, 1) + 1;
}
for (i = 0; i < count; i++)
{
string_builder.Append(int_parser[i]);
}
}
private static int ToCharArray(uint value, char[] buffer, int bufferIndex)
{
if (value == 0)
{
buffer[bufferIndex] = '0';
return 1;
}
int len = 1;
for (uint rem = value / 10; rem > 0; rem /= 10)
{
len++;
}
for (int i = len - 1; i >= 0; i--)
{
buffer[bufferIndex + i] = (char)('0' + (value % 10));
value /= 10;
}
return len;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 選擇使用SpeedString來在Update()中進(jìn)行賦值(或戰(zhàn)斗中血條的顯示及技能CD)
使用NGUI遇到的問題:
(1). UILabel.text = str不會(huì)刷新界面。
原因:NGUI中text賦值的實(shí)現(xiàn)如 代碼2:(由于使用SpeedString后,給NGUI反復(fù)賦值都是使用的同一個(gè)string內(nèi)存空間(SpeedString.string_base),因此mText == value始終為true,為了刷新界面,提出更改的部分,實(shí)現(xiàn)如 代碼3)
代碼2
public string text
{
get
{
return mText;
}
set
{
if (mText == value) return;
if (string.IsNullOrEmpty(value))
{
if (!string.IsNullOrEmpty(mText))
{
mText = "";
MarkAsChanged();
ProcessAndRequest();
}
}
else if (mText != value)
{
mText = value;
MarkAsChanged();
ProcessAndRequest();
}
if (autoResizeBoxCollider) ResizeCollider();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
代碼3
public void SetText(string _text, bool bForce = false)
{//3.7.7
if (bForce)
{
if(mText != _text)
mText = _text;
MarkAsChanged();
ProcessAndRequestForce();
if (autoResizeBoxCollider) ResizeCollider();
}
else
this.text = _text;
}
對(duì)NGUI 3.9.7版本的,使用如下代碼:
public void SetText(string _text, bool bForce = false)
{
if (bForce)
{
if (mText != _text || mProcessedText!=_text)
{
mText = _text;
mProcessedText = _text;
}
MarkAsChanged();
ProcessAndRequestForce();
if (autoResizeBoxCollider) ResizeCollider();
}
else
this.text = _text;
}
ProcessAndRequestForce是對(duì)NGUI中的又已修改,因?yàn)槭褂玫脑璓rocessAndRequest過程發(fā)現(xiàn),UILabel中的void ProcessText (bool legacyMode, bool full)會(huì)導(dǎo)致內(nèi)存分配,為了避免,修改了這個(gè)函數(shù)
void ProcessText (bool legacyMode, bool full,bool bFroce = false)
{
//........省略.....................
// Wrap the text
bool fits = true;
if ( !bFroce || (mText != mProcessedText && bFroce))
fits = NGUIText.WrapText(mText, out mProcessedText, true);
//........省略.....................
}
void ProcessAndRequestForce()
{
#if UNITY_EDITOR
if (!Application.isPlaying && !NGUITools.GetActive(this)) return;
if (!mAllowProcessing) return;
#endif
if (ambigiousFont != null) ProcessText(false, true,true);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
最后就將給UILabel賦值的內(nèi)存分配降低到了0。
///////
關(guān)于 讀者提出的修改SetText的方法的問題:
public void SetText(string _text,bool bForce = false)
{
if(bForce)
{
if (mText != _text)
mText = _text;
MarkAsChanged();
ProcessAndRequestForce();
if (autoResizeBoxCollider) ResizeCollider();
}
{
text = _text;
}
}
public void SetTextNew(string _text, bool bForce = false)
{
if (bForce)
{
if (mText != _text)
{
mText = _text;
ProcessAndRequestForce();
}
MarkAsChanged();
if (autoResizeBoxCollider) ResizeCollider();
}
{
text = _text;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
原代碼的測(cè)試結(jié)果
讀者的測(cè)試結(jié)果
內(nèi)存中多了UIPanelLateUpdate中的內(nèi)存消耗。
謝謝 hyf2713 提出不同的方法,有問題希望大家提出,或者有更好的修改方法