我有一个简单的程序,它从数据库中获取数据并通过DataAdapter.Fill()将其存储在DataSet中。
我面临的问题是程序的内存大小不断增加。使用进程资源管理器,我监视程序的虚拟大小。这些过程在独立版本中运行(不在统一编辑器中)。
程序启动后2分钟,程序的虚拟大小为824,444K,但程序运行30分钟,程序的虚拟大小增加到1,722,340K。
(无法上传屏幕截图)https://drive.google.com/open?id=0B0DwzunTEqfKcDhHcXRmV2twUEE
程序只包含2个简单的脚本:一个辅助类SQLController,用于管理从数据库到数据集的加载,以及一个单行动脚本DataProducer,它定期轮询数据库,使用SQLController对象进行“更新”。
SQLController:
if ($result > 0) {
while($row = $stmt->fetch()) {
//SETUP HOURS FOR EACH DAY
$timesSun = $row['sunday'];
$timesMon = $row['monday'];
$timesTue = $row['tuesday'];
$timesWed = $row['wednesday'];
$timesThu = $row['thursday'];
$timesFri = $row['friday'];
$timesSat = $row['saturday'];
//SEPARATE DAY & NIGHT
$sepDNsun = explode('/',$timesSun);
$sepDNmon = explode('/',$timesMon);
$sepDNtue = explode('/',$timesTue);
$sepDNwed = explode('/',$timesWed);
$sepDNthu = explode('/',$timesThu);
$sepDNfri = explode('/',$timesFri);
$sepDNsat = explode('/',$timesSat);
//SEPARATE OPEN AND CLOSE
$daySun = explode('to',$sepDNsun[0]);
$nightSun = explode('to',$sepDNsun[1]);
$dayMon = explode('to',$sepDNmon[0]);
$nightMon = explode('to',$sepDNmon[1]);
$dayTue = explode('to',$sepDNtue[0]);
$nightTue = explode('to',$sepDNtue[1]);
$dayWed = explode('to',$sepDNwed[0]);
$nightWed = explode('to',$sepDNwed[1]);
$dayThu = explode('to',$sepDNthu[0]);
$nightThu = explode('to',$sepDNthu[1]);
$dayFri = explode('to',$sepDNfri[0]);
$nightFri = explode('to',$sepDNfri[1]);
$daySat = explode('to',$sepDNsat[0]);
$nightSat = explode('to',$sepDNsat[1]);
//SET OPEN & CLOSE
$dayOpenSun = $daySun[0];
$dayCloseSun = $daySun[1];
$nightOpenSun = $nightSun[0];
$nightCloseSun = $nightSun[1];
$dayOpenMon = $dayMon[0];
$dayCloseMon = $dayMon[1];
$nightOpenMon = $nightMon[0];
$nightCloseMon = $nightMon[1];
$dayOpenTue = $dayTue[0];
$dayCloseTue = $dayTue[1];
$nightOpenTue = $nightTue[0];
$nightCloseTue = $nightTue[1];
$dayOpenWed = $dayWed[0];
$dayCloseWed = $dayWed[1];
$nightOpenWed = $nightWed[0];
$nightCloseWed = $nightWed[1];
$dayOpenThu = $dayThu[0];
$dayCloseThu = $dayThu[1];
$nightOpenThu = $nightThu[0];
$nightCloseThu = $nightThu[1];
$dayOpenFri = $dayFri[0];
$dayCloseFri = $dayFri[1];
$nightOpenFri = $nightFri[0];
$nightCloseFri = $nightFri[1];
$dayOpenSat = $daySat[0];
$dayCloseSat = $daySat[1];
$nightOpenSat = $nightSat[0];
$nightCloseSat = $nightSat[1];
//SET STORE OPENING HOURS
$storeSchedule = [
'Sun' => [$dayOpenSun => $dayCloseSun, $nightOpenSun => $nightCloseSun],
'Mon' => [$dayOpenMon => $dayCloseMon, $nightOpenMon => $nightCloseMon],
'Tue' => [$dayOpenTue => $dayCloseTue, $nightOpenTue => $nightCloseTue],
'Wed' => [$dayOpenWed => $dayCloseWed, $nightOpenWed => $nightCloseWed],
'Thu' => [$dayOpenThu => $dayCloseThu, $nightOpenThu => $nightCloseThu],
'Fri' => [$dayOpenFri => $dayCloseFri, $nightOpenFri => $nightCloseFri],
'Sat' => [$dayOpenSat => $dayCloseSat, $nightOpenSat => $nightCloseSat]
];
// current or user supplied UNIX timestamp
$timestamp = time();
// default status
$status = $lang["NO-READY"];
// get current time object
$currentTime = (new DateTime())->setTimestamp($timestamp);
// loop through time ranges for current day
foreach ($storeSchedule[date('D', $timestamp)] as $startTime => $endTime) {
// create time objects from start/end times
$startTime = DateTime::createFromFormat('G:i', $startTime);
$endTime = DateTime::createFromFormat('G:i', $endTime);
// check if current time is within a range
if (($startTime < $currentTime) && ($currentTime < $endTime)) {
$status = $lang["READY"];
break;
}
}
//OUTPUT CONTENT
echo '<li>
<div class="rest-list-content">
<a href="'. $location .'/restaurants/'. $row["rest_url"] .'">
<img src="images/all_rest/'. $row["rest_logo"] .'" alt="'. $row["rest_name"] .'">
<h1>'. $row["rest_name"] .'</h1>
<p>Cuisine: <span>'. $row["cuisine_name"] .'</span></p>
<p>Minimun Order: <span>$'. $row["rest_min_order"] .'</span></p>
<p class="availability">'. $status .'</p>
</a>
</div>
</li>';
}
} else {
echo "0 results";
}
DataProducer
using UnityEngine;
using System.Collections;
using System.Data;
using System.Data.Sql;
using System.Data.SqlClient;
using UnityEngine.UI;
using System.Threading;
public class SQLController {
string connectionString;
string dataSource, catalog, uid, pwd;
DataSet dat_set;
public SQLController(string dataSource, string catalog, string uid, string pwd)
{
this.dataSource = dataSource;
this.catalog = catalog;
this.uid = uid;
this.pwd = pwd;
}
/// <summary>
/// Open a connectio to the database and query it for data with the statement input
/// </summary>
/// <param name="statement"> The query statement to be used to query the server</param>
/// <returns></returns>
public DataSet Load(string statement, string name)
{
connectionString = string.Format("data source={0};initial catalog={1};uid={2};pwd={3}", dataSource, catalog, uid, pwd);
using (SqlConnection dbcon = new SqlConnection(connectionString))
using (SqlDataAdapter dataAdapter = new SqlDataAdapter(statement, dbcon))
{
dat_set = new System.Data.DataSet();
dbcon.Open();
dataAdapter.Fill(dat_set, name);
}
return dat_set;
}
}
我不确定究竟是什么导致了内存泄漏,但是当我从线程
更改了加载时 using UnityEngine;
using System.Collections;
using System.Threading;
using System.Data;
using UnityEngine.UI;
using SimpleJSON;
public class DataProducer : MonoBehaviour {
public GameObject textObj;
private string[] _configData;
private string _outputText;
private SQLController _sqlController;
private bool _toggle = true;
private bool _updating = false;
private DataSet _dataSetCache;
private Thread _dataGrabThread;
// Use this for initialization
void Start () {
_configData = new string[5];
if (LoadFromConfigFile())
{
StartCoroutine(LoadFromDB());
}
}
// Update is called once per frame
void Update () {
textObj.GetComponent<Text>().text = _outputText;
}
public void OnDisable()
{
// stop any running thread
if (null != _dataGrabThread && _dataGrabThread.IsAlive)
{
_dataGrabThread.Abort();
}
}
IEnumerator LoadFromDB()
{
while (true)
{
if (_updating)
{
Debug.Log("Data System Poll DataBase ignored");
}
else
{
_updating = true;
_dataGrabThread = new Thread(Load);
_dataGrabThread.IsBackground = true;
_dataGrabThread.Start();
}
yield return new WaitForSeconds(10f);
}
}
void Load()
{
string statement;
if (_toggle)
{
_toggle = !_toggle;
statement = "SELECT TOP 100000 [AIIDX],[LASTATTACKDATE],[LASTRECEIVEDDATE],[DEVICEID],[INSTANCES],[ATTACKTYPE],[SEVERITY],[STATUS] FROM AI (NOLOCK)";
}
else
{
_toggle = !_toggle;
statement = "SELECT TOP 100000 [AIIDX],[LASTATTACKDATE],[LASTRECEIVEDDATE],[DEVICEID],[SEVERITY],[STATUS] FROM AI (NOLOCK)";
}
_sqlController = new SQLController(_configData[0], _configData[1], _configData[2], _configData[3]);
_outputText = "Loading";
_dataSetCache = _sqlController.Load(statement, "TestObject");
PrintDataSet();
_updating = false;
}
/// <summary>
/// Convert datatable into string and print it out through a text object
/// </summary>
void PrintDataSet()
{
if (null == _dataSetCache)
{
return;
}
DataTable dt = _dataSetCache.Tables["TestObject"];
if (null == dt)
{
return;
}
System.Text.StringBuilder builder = new System.Text.StringBuilder();
for (int i = 0; i < 20; ++i)
{
builder.AppendFormat("{0,-5}", (i + 1) + ".");
//comp.text += string.Format("{0,-5}", (i + 1) + ".");
DataRow dr = dt.Rows[i];
for (int j = 0; j < dt.Columns.Count; ++j)
{
builder.AppendFormat("{0, -30}", dr[dt.Columns[j]].ToString());
}
builder.Append("\n");
}
_outputText = builder.ToString();
builder = null;
}
bool LoadFromConfigFile()
{
string line;
using (System.IO.StreamReader file = new System.IO.StreamReader("./config.txt"))
{
if (file == null)
{
return false;
}
int index = 0;
while ((line = file.ReadLine()) != null)
{
if (index > _configData.Length)
{
Debug.LogError("Invalid Config file");
return false;
}
_configData[index++] = line;
}
//if the config file does not consist of 5 data
if (index < _configData.Length)
{
Debug.LogError("Invalid Config file");
return false;
}
return true;
}
}
}
在主线程中运行,
_dataGrabThread = new Thread(Load);
进程虚拟大小虽然仍然增加,但速度较慢。从828,312K,2分钟到1,083,908K,40分钟。