원래 싱글톤은 크게 시작될때 바로 생성과 처음 사용될때에 생성이 있다.
여기서 문제점은 이 싱글톤들은 생성된 시점부터 사라지지않고 메모리를 차지한다. 그래서 약한참조 싱글톤이 있다.
using System;
using UnityEngine;
public class DamageableManager
{
private int strDamage = 1;
private int strMaxHealth = 1;
private int agiDamage = 1;
private int agiCritDamage = 1;
private int agiCritChance = 1;
private int vitMaxHealth = 1;
private int vitDefense = 1;
private static WeakReference<DamageableManager> instance;
private DamageableManager() { }
public static DamageableManager Instance
{
get
{
if (instance == null || !instance.TryGetTarget(out var singleton))
{
singleton = new DamageableManager();
instance = new WeakReference<DamageableManager>(singleton);
}
return singleton;
}
}
public void CalculateTotalDamage(CharacterStats myStats, CharacterStats enemyStats, float attackPower)
{
float totalDamage;
totalDamage = GetDamage(myStats) * attackPower;
if (CanCrit(myStats))
{
totalDamage *= (GetCritDamage(myStats) / 100);
}
totalDamage = CheckTargetDefense(totalDamage, enemyStats);
enemyStats.DecreaseHealth((int)totalDamage);
}
public bool CanCrit(CharacterStats myStats)
{
if (GetCritChance(myStats) > UnityEngine.Random.Range(0, 100))
{
return true;
}
return false;
}
public float CheckTargetDefense(float totalDamage, CharacterStats enemyStats)
{
totalDamage -= totalDamage * (GetDefense(enemyStats) / (GetDefense(enemyStats) + 50));
return totalDamage;
}
#region Get Stats
public int GetDamage(CharacterStats Stats)
{
return Stats.damage.GetValue() +
(Stats.strength.GetValue() * strDamage + Stats.agility.GetValue() * agiDamage);
}
public float GetDefense(CharacterStats stats)
{
return stats.defense.GetValue() +
stats.vitality.GetValue() * vitDefense;
}
public int GetMaxHealth(CharacterStats stats)
{
return stats.maxHealth.GetValue() +
stats.vitality.GetValue() * vitMaxHealth + stats.strength.GetValue() * strMaxHealth;
}
public int GetCritChance(CharacterStats stats)
{
return stats.critChance.GetValue() +
stats.agility.GetValue() * agiCritChance;
}
public int GetCritDamage(CharacterStats stats)
{
return stats.critDamage.GetValue() +
stats.agility.GetValue() * agiCritDamage;
}
#endregion
}
데미지 계산을 static Class로 하였는데 이는 계속 메모리누수가 발생할 수 있어서 피하고 싶었다.
그래서 약한 참조 싱글톤을 생성하여 관리하도록 하였다.
약한참조 싱글톤은 GC(가비지 컬렉터)가 삭제할 수 있는 싱글톤이다.
그래서 사용하지 않을 때에는 GC가 삭제해주기에 메모리 누수를 방지 할 수 있다.
하지만 반대로 GC가 삭제하기에 nullError가 일어날 가능성이 있다.
그래서 nullCheck을 해줘야 안전하게 사용 가능하다.
약한참조이기에 static Class처럼 이전 내용이 저장되지않는다.
그래서 이전의 행동과 같은 데이터가 많이 필요없고 데미지 계산이 위주이기 때문에 약한참조 싱글톤을 제작하였다.
하지만 나중에 저장해야 하는 시스템을 만든다고 하면 언제든 static class로도 돌아갈 수 있도록 준비는 해둬야겠다.
약한 참조 싱글톤은 처음 써보는데 메모리 누수 방지 역할을 한다는 거에 일단 마음이 너무 편안해 졌다.
요즘 뭔가 최적화... 최적화...만을 찾고 있는데 딱 좋은 예시가 들어와 준 것 같아서 너무좋다.
물론 사용할 때에 주의가 필요하겠지만 내가 주의를 잘하면 해결될 문제이다.
(static 메모리 누수는 내가 주의 할 수 없다...)