執行緒中使用全域變數,發現記憶體不釋放,GC也不管用
uj5u.com熱心網友回復:
1.是不是應該把代碼貼上來2.從的問題中 我能想到的就是 比如有一個全域變數 a 它的宣告周期是 a所在的物件被創建一直到a所在的物件在程式中沒有參考(GC會處理a所在物件的記憶體 a的記憶體連帶著被處理掉了) 如果a所在的物件一直在被參考 a的記憶體不釋放不是很正常嗎,如果這個時候 a突然被釋放那么你才應該去深究它
uj5u.com熱心網友回復:
private bool BulkDB(){
List<OPCData> datalist = new List<OPCData>();
for (int i = 0; i < 210; i++)
{
OPCData model = new OPCData();
model.Item = "你好" + i;
model.DataValue = i * Math.Round(100d);
model.TimeStamp = DateTime.Now.ToString();
model.Qualitie = 192;
datalist.Add(model);
}
DataTable APGatherData = new DataTable();
APGatherData.Columns.Add("ParamID", typeof(int));
APGatherData.Columns.Add("ClientID", typeof(string));
APGatherData.Columns.Add("EqtID", typeof(int));
APGatherData.Columns.Add("WSID", typeof(int));
APGatherData.Columns.Add("ParamName", typeof(string));
APGatherData.Columns.Add("ParamValue", typeof(string));
APGatherData.Columns.Add("PackageTime", typeof(DateTime));
APGatherData.Columns.Add("InsertTime", typeof(DateTime));
APGatherData.Columns.Add("Qualitie", typeof(int));
APGatherData.Columns.Add("Interval", typeof(int));
string tabname = "tb_gatherFaultReleSign1";
//DataTable dtm = this.APGatherData.Clone();
List<DataRow> insertRows = new List<DataRow>();
foreach (OPCData dt in datalist)
{
//資料處理
//DataRow row = dtm.NewRow();
DataRow row = APGatherData.NewRow();
row["ClientID"] = "";
if (dt.Item != null)
{ row["ParamName"] = dt.Item; }
else
{
row.Delete();
continue;
}
if (dt.DataValue != null)
{ row["ParamValue"] = DeepCopyByReflect(dt.DataValue); }//.ToString();
else
{
row.Delete();
continue;
}
if (dt.TimeStamp != null)
{ row["PackageTime"] = dt.TimeStamp; }
else
{
row["PackageTime"] = DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToString("HH:mm:ss.fff");
}
row["InsertTime"] = DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToString("HH:mm:ss.fff");
row["Qualitie"] = dt.Qualitie;
row["Interval"] = 0;
PlcOwner md;
tbMacShop.TryGetValue(dt.Item.ToLower(), out md);
if (md != null)
{
row["EqtID"] = md.EqtId;
row["WSID"] = md.WSId;
row["ParamID"] = md.ID;
}
else
{
row["EqtID"] = 0;
row["WSID"] = 0;
row["ParamID"] = 0;
}
insertRows.Add(row);
}
datalist.Clear();
datalist = null;
bool result = false;
SqlBulkCopy bulkCopy = new SqlBulkCopy(connection.ConnectionString);
bulkCopy.DestinationTableName = tabname;
bulkCopy.ColumnMappings.Add("ParamID", "ParamID");
bulkCopy.ColumnMappings.Add("ClientID", "ClientID");
bulkCopy.ColumnMappings.Add("EqtID", "EqtID");
bulkCopy.ColumnMappings.Add("WSID", "WSID");
bulkCopy.ColumnMappings.Add("ParamName", "ParamName");
bulkCopy.ColumnMappings.Add("ParamValue", "ParamValue");
bulkCopy.ColumnMappings.Add("PackageTime", "PackageTime");
bulkCopy.ColumnMappings.Add("InsertTime", "InsertTime");
bulkCopy.ColumnMappings.Add("Qualitie", "Qualitie");
bulkCopy.ColumnMappings.Add("Interval", "Interval");
try
{
bulkCopy.BatchSize = 1000;
DataRow[] rows = insertRows.ToArray();
Stopwatch sw = new Stopwatch();
sw.Start();
bulkCopy.WriteToServer(rows);
//Thread.Sleep(70);
bulkCopy.Close();
bulkCopy = null;
sw.Stop();
for (int i = 0; i < rows.Length; i++)
{
rows[i] = null;
}
rows = null;
logger.Info(sw.ElapsedMilliseconds);
result = true;
}
catch (Exception ex)
{
bulkCopy.Close();
bulkCopy = null;
logger.Error("定時資料SqlBulkCopy處理錯誤,原因:" + ex.Message);
}
finally
{
DoCount = DoCount + insertRows.Count;
}
Thread.Sleep(10);
insertRows.Clear();
insertRows = null;
//dtm.Clear();
//dtm.Dispose();
//dtm = null;
APGatherData.Clear();
APGatherData.Dispose();
APGatherData = null;
GC.Collect();
//GC.WaitForPendingFinalizers();
return result;
}
uj5u.com熱心網友回復:
每秒執行一次,發現記憶體在不斷增加,GC無效uj5u.com熱心網友回復:
呼叫無效,沒有任何證據證明你的說法。需要比對除錯快照如果你不愿意去找證據,我們只能讓你先40秒一次看看,或者先跑2小時看看
ps:記憶體增加并不是那些人說的“壞事”,壞的事一直增加。假設2個小時,他從來就沒減過,而且一直加。那是壞事。但是20分鐘后他會逐漸穩定下來,這只能說明,“起步加速”達到平衡點,需要時間,而不是說明“代碼很臭”
uj5u.com熱心網友回復:
已經跑了1個多月了,記憶體在一直增加,原函式BulkDB(List<OPCData> datalist)其中引數datalist是全域變數,外面給值,BulkDB在執行緒中運行。為了測驗去掉外面給值,發現記憶體一樣增加uj5u.com熱心網友回復:
這只能說明,1s不夠處理。
開源節流
1.開源,分塊并行處理,加快處理速度。
2.節流,加入限流鎖。進行限流操作
uj5u.com熱心網友回復:
是程式一直跑跑了一個多月 比如記憶體 從100M漲到2G 還是說程式跑了一個月 但是斷斷續續的跑的uj5u.com熱心網友回復:
因為現在從你代碼沒看出什么會漲記憶體的地方 除非你的函式 執行時間>呼叫間隔 但即使是這樣 應該也是有一個上限的uj5u.com熱心網友回復:
1s不夠處理 不夠是什么意思?bulkCopy.WriteToServer(rows)用不了1s啊uj5u.com熱心網友回復:
記憶體到1.6G就重新啟動再次跑
uj5u.com熱心網友回復:
比如BulkDB這個函式執行需要10秒 而你呼叫頻率是1秒1次 那么你程式中會同時存在10個這個BulkDB這個函式 如果一個函式需要的記憶體是10M 那么 10個就是100M 程式運行一段時間后 會從 初始 比如是100 漲到200 不考慮其他的記憶體 但是到200之后就穩定了 不會再漲了uj5u.com熱心網友回復:
你說漲到1.6G是多久漲到1.6G的 這個增長趨勢是什么樣的 如果每天都在漲 比如第一天100M 第二天200M 第三天300M 以此類推 一個月都是這樣 那么肯定是程式有問題了但是如果 第一天直接起始100M 一定時間內跑到了1.6G 之后一直到第三十天 還是1.6G 那么就是你程式就是需要這1.6G記憶體 是沒有關系的
uj5u.com熱心網友回復:
private void DataProc(){
while (true)
{
try
{
List<OPCData> temp = null;
lock (objLock)
{
temp = OPCDataList;
OPCDataList = new List<OPCData>();
}
BulkDB(temp);
temp.Clear();
temp = null;
GC.Collect();
}
catch (Exception ex)
{
logger.Error(ex.Message + ex.StackTrace + ex.Source, ex);
}
Thread.Sleep(5000);
}
}
OPCDataList 是全域變數,DataProc 是一個執行緒 ,應該不存在BulkDB并發的情況
uj5u.com熱心網友回復:
這就是我們讓你對比快照的原因了,我們需要知道,到底是OPCDataList在增加還是BulkDB在增加。
首先需要知道證據,我們才能知道怎么進行下一步
uj5u.com熱心網友回復:
記憶體是在不停的增長的,跑到1.6G程式就崩了uj5u.com熱心網友回復:
1、單獨測驗BulkDB,不用外部全域變數,在函式內寫測驗資料,記憶體增加;2、注釋掉BulkDB中的bulkCopy.WriteToServer(rows),記憶體不增加了;
3、使用DataProc()外部傳入資料,記憶體增加
uj5u.com熱心網友回復:
using (SqlBulkCopy bulkCopy =new SqlBulkCopy(destinationConnection))使用using來創建,然后測驗一下看看。
具體的你看連接
https://blog.csdn.net/hanjun0612/article/details/70689753
uj5u.com熱心網友回復:
測驗了,濤聲依舊
uj5u.com熱心網友回復:
你把OPCDataList = new List<OPCData>(); 換成 BlockingCollection<OPCData>再試試看
uj5u.com熱心網友回復:
using (SqlBulkCopy bulkCopy =new SqlBulkCopy(destinationConnection))
使用using來創建,然后測驗一下看看。
具體的你看連接
https://blog.csdn.net/hanjun0612/article/details/70689753
測驗了,濤聲依舊
你把OPCDataList = new List<OPCData>(); 換成 BlockingCollection<OPCData>再試試看
看不出效果
uj5u.com熱心網友回復:
看上去,你是要寫一個資料采集代碼(資料爬蟲)。關鍵的缺陷是資料格式設計的不好,冗余資料太多,有些資料可以在服務器端處理,只要標記一下終端號就可以自動生成。另外,這種程式如果采集到重要線索,服務器可能會直接介入管理;出現問題,要向服務器報告,服務器的一些操作需要協商告知。uj5u.com熱心網友回復:
厲害鍵的缺陷是資料格式設計的不好,冗余資料太多,有些資料可以在服務器端處理uj5u.com熱心網友回復:
https://www.lanhusoft.com/Article/15.htmluj5u.com熱心網友回復:
https://www.lanhusoft.com/Article/15.html
我的問題不是檔案大,而是寫入頻繁,導致記憶體不斷上漲。
uj5u.com熱心網友回復:
看上去,你是要寫一個資料采集代碼(資料爬蟲)。關鍵的缺陷是資料格式設計的不好,冗余資料太多,有些資料可以在服務器端處理,只要標記一下終端號就可以自動生成。另外,這種程式如果采集到重要線索,服務器可能會直接介入管理;出現問題,要向服務器報告,服務器的一些操作需要協商告知。
是資料采集代碼,但是格式沒有辦法改
uj5u.com熱心網友回復:
using (SqlBulkCopy bulkCopy =new SqlBulkCopy(destinationConnection))
使用using來創建,然后測驗一下看看。
具體的你看連接
https://blog.csdn.net/hanjun0612/article/details/70689753
目前發現可能與using (SqlBulkCopy bulkCopy =new SqlBulkCopy(destinationConnection)) 有關系,但是好像還需要bulkCopy.close() 和合適的sleep() 時間,還需要跑上一段時間看結果。
uj5u.com熱心網友回復:
1、單獨測驗BulkDB,不用外部全域變數,在函式內寫測驗資料,記憶體增加;
2、注釋掉BulkDB中的bulkCopy.WriteToServer(rows),記憶體不增加了;
3、使用DataProc()外部傳入資料,記憶體增加
一樣的,既然是你自已都定位出來是bulkCopy.WriteToServer(rows)的問題,為什么不改一下?
uj5u.com熱心網友回復:
1、單獨測驗BulkDB,不用外部全域變數,在函式內寫測驗資料,記憶體增加;
2、注釋掉BulkDB中的bulkCopy.WriteToServer(rows),記憶體不增加了;
3、使用DataProc()外部傳入資料,記憶體增加
一樣的,既然是你自已都定位出來是bulkCopy.WriteToServer(rows)的問題,為什么不改一下?
bulkCopy.WriteToServer(rows)必須用,但需要解決記憶體增加的問題
uj5u.com熱心網友回復:
1、單獨測驗BulkDB,不用外部全域變數,在函式內寫測驗資料,記憶體增加;
2、注釋掉BulkDB中的bulkCopy.WriteToServer(rows),記憶體不增加了;
3、使用DataProc()外部傳入資料,記憶體增加
一樣的,既然是你自已都定位出來是bulkCopy.WriteToServer(rows)的問題,為什么不改一下?
或者有類似的方法可用?
uj5u.com熱心網友回復:
學習了~~~uj5u.com熱心網友回復:
在黑客技術里,通過外部執行緒呼叫阻止記憶體釋放以及代碼卸載、是比較基礎和常見的做法。你這里的情況很可能就是服務器端阻止了任務卸載和記憶體釋放。bulkCopy 是資料塊操作,使用的是通過緩沖準備資料、然后批量傳輸的操作方案。其操作執行可能會有延遲,但是執行程序很快。從你的資料量看,每次操作時間都會很短,不太會出現因為系統性能不夠而配合失序的可能。uj5u.com熱心網友回復:
看樓主的情況,應該就是沒使用using的問題了uj5u.com熱心網友回復:
看樓主的情況,應該就是沒使用using的問題了
經過測驗,不是using的問題
uj5u.com熱心網友回復:
在黑客技術里,通過外部執行緒呼叫阻止記憶體釋放以及代碼卸載、是比較基礎和常見的做法。你這里的情況很可能就是服務器端阻止了任務卸載和記憶體釋放。bulkCopy 是資料塊操作,使用的是通過緩沖準備資料、然后批量傳輸的操作方案。其操作執行可能會有延遲,但是執行程序很快。從你的資料量看,每次操作時間都會很短,不太會出現因為系統性能不夠而配合失序的可能。
問題定位了,有什么解決辦法嗎?
uj5u.com熱心網友回復:
是不是有其它物件參考了?uj5u.com熱心網友回復:
支持,好文章uj5u.com熱心網友回復:
private void DataProc()
{
while (true)
{
try
{
List<OPCData> temp = null;
lock (objLock)
{
temp = OPCDataList;
OPCDataList = new List<OPCData>();
}
BulkDB(temp);
temp.Clear();
temp = null;
GC.Collect();
}
catch (Exception ex)
{
logger.Error(ex.Message + ex.StackTrace + ex.Source, ex);
}
Thread.Sleep(5000);
}
}
OPCDataList 是全域變數,DataProc 是一個執行緒 ,應該不存在BulkDB并發的情況
代碼邏輯有問題,temp 作為引數傳入到執行緒函式中,執行緒可能還未執行完畢,馬上就被清空了。
uj5u.com熱心網友回復:
private void DataProc()
{
while (true)
{
try
{
List<OPCData> temp = null;
lock (objLock)
{
temp = OPCDataList;
OPCDataList = new List<OPCData>();
}
BulkDB(temp);
temp.Clear();
temp = null;
GC.Collect();
}
catch (Exception ex)
{
logger.Error(ex.Message + ex.StackTrace + ex.Source, ex);
}
Thread.Sleep(5000);
}
}
OPCDataList 是全域變數,DataProc 是一個執行緒 ,應該不存在BulkDB并發的情況
代碼邏輯有問題,temp 作為引數傳入到執行緒函式中,執行緒可能還未執行完畢,馬上就被清空了。
測驗過沒有問題
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/32859.html
標籤:C#
上一篇:如何實作這樣的需求,謝謝
