समस्याहैंडल रिसाव के स्रोत का पता लगाने के लिए कैसे
मैं सिर्फ कल कुछ प्रदर्शन लॉगिंग में डाल के रूप में मैं, कार्य प्रबंधक देख काफी कुछ समय पहले से एक हैंडल रिसाव देखा हालांकि यह फिक्सिंग कम प्राथमिकता किया गया है। यह प्रत्येक 10 सेकंड में एक नमूना के साथ एक रातोंरात दौड़ है।
मैंने अभी तक विफलता के लिए इसे नहीं चलाया है, समय की बाधाओं के कारण और मेरा टेस्ट कंप्यूटर भी मेरा देव कंप्यूटर है इसलिए कोड लिखते समय इसे चलाना आदर्श नहीं है ... इसलिए मुझे यकीन नहीं है कि यह कब होगा दुर्घटना, लेकिन मुझे अत्यधिक संदेह है कि यह केवल समय की बात है।
नोट: लाल क्षेत्र में बॉक्सिंग वह जगह है जहाँ मैं काम कर पाश "बंद कर दिया" और एक छोटी विराम के बाद इसे पुन: प्रारंभ। थ्रेड "स्टॉप" पर ~ 100 से ~ 20 तक गिर गए। हैंडल तब तक नहीं गिरते जब तक कि लूप को ~ 62,000 से ~ 40,000 तक लगभग 30 सेकंड के बाद पुनरारंभ नहीं किया गया। तो कुछ हैंडल जीसीएड प्राप्त कर रहे हैं, जितना मैं उम्मीद करता हूं उतना ही नहीं। मैं यह नहीं समझ सकता कि इन सभी हैंडल को एकत्रित होने से या जहां वे मूल रूप से आ रहे हैं (यानी कार्य, जीयूआई, फाइल इत्यादि) से कौन सा रूट रोक रहा है।
यदि आपके पास पहले से ही कोई विचार है कि इस समस्या का कारण क्या हो सकता है, तो आगे पढ़ने की आवश्यकता नहीं है। मैंने इस मुद्दे को सुलझाने के शॉट-गन शैली दृष्टिकोण में संदर्भ के लिए शेष जानकारी और कोड प्रदान किया है। मैं हटा दूंगा, संपादित कर सकता हूं, क्योंकि मूल कारण कम हो गया है। एक ही टोकन द्वारा, यदि कुछ ब्याज गुम है तो मुझे बताएं और मैं इसे प्रदान करने की कोशिश करूंगा (लॉग, डंप इत्यादि)।
व्हॉट आई हैव डन
अपने ही मैं Tracking Handle Misuse पर इस ट्यूटोरियल के माध्यम से चला और मिल गया है पर जहाँ तक खोजने के लिए जहां हैंडल खुला और बंद डंप फ़ाइलों को देख के रूप में ... हालांकि यह हजारों हैंडल के साथ बहुत जबरदस्त था और मुझे कोई समझ नहीं आया और मुझे लोड करने के लिए प्रतीक प्राप्त करने में परेशानी थी, इसलिए पॉइंटर्स सिर्फ मेरे लिए चिंतित थे।
मैं के माध्यम से अपनी सूची में निम्नलिखित दो जाना अभी तक नहीं है, लेकिन अगर कोई दोस्ताना तरीकों पहले थे सोचा ...
- Debug Leaky Apps: Identify And Prevent Memory Leaks In Managed Code
- Tracking down managed memory leaks (how to find a GC leak)
मैं भी है कोड को विभाजित करें, मुझे इस बात का एक और छोटा एप्लीकेशन में संभावित कारण होने का संदेह है और सब कुछ बिना किसी मुद्दे के कचरा इकट्ठा करने के लिए दिखाई देता है (यद्यपि निष्पादन पैटर्न वास्तविक ऐप की तुलना में बहुत सरल था)।
संभावित अपराधियों
मैं 5 फार्म कि केवल एक बार बनाई गई हैं प्रत्येक और फिर छिपा/रूप में की जरूरत दिखाया सहित कई लंबे समय से रहते थे instanced कक्षाएं कि जब तक आवेदन के लिए खुला है पिछले, है। मैं अपने ऑब्जेक्ट कंट्रोलर के रूप में एक मुख्य ऑब्जेक्ट का उपयोग करता हूं और फिर मॉडल और व्यूज़ प्रेजेंटर्स-फर्स्ट पैटर्न में प्रस्तुतियों के ईवेंट के माध्यम से वायर्ड होते हैं।
- बड़े पैमाने पर उपयोग कस्टम
Action
,Func
और lambdas, जिनमें से कुछ लंबे समय से रहते थे - 3 कस्टम हो सकता है:
नीचे कुछ चीजें मैं इस आवेदन, जो या महत्वपूर्ण नहीं हो सकता में क्या कर रहे हैं घटनाओं के लिए प्रतिनिधि और जो
Task
एस एसिंक निष्पादन के लिए उत्पन्न कर सकते हैं। Controls
पर सुरक्षित रूप से आमंत्रित करने के लिए एक्सटेंशन।- बहुत, बहुत भारी
Task
औरParallel.For
/Parallel.Foreach
कार्यकर्ता तरीकों को चलाने के लिए (या घटनाओं के रूप में ऊपर उल्लेख किया है) का उपयोग - कभी Thread.Sleep (का उपयोग करें), लेकिन इसके बजाय एक कस्टम Sleep.For() जो एक AutoResetEvent उपयोग करता है।
मुख्य लूप
इस आवेदन जाता है जब यह रनिंग के सामान्य प्रवाह ऑफलाइन संस्करण में फ़ाइलों की एक श्रृंखला और एक डिजिटल इनपुट संकेत के मतदान पर एक पाश पर आधारित है ऑनलाइन संस्करण में। नीचे ऑफ़लाइन संस्करण के लिए टिप्पणियों के साथ सुडो-कोड है जो बाहरी लैपटॉप की आवश्यकता के बिना मैं अपने लैपटॉप से चला सकता हूं और उपरोक्त चार्ट क्या निगरानी कर रहा था (मेरे पास ऑनलाइन के लिए हार्डवेयर तक पहुंच नहीं है इस समय मोड)।
public void foo()
{
// Sudo Code
var InfiniteReplay = true;
var Stopped = new CancellationToken();
var FileList = new List<string>();
var AutoMode = new ManualResetEvent(false);
var CompleteSignal = new ManualResetEvent(false);
Action<CancellationToken> PauseIfRequired = (tkn) => { };
// Enumerate a Directory...
// ... Load each file and do work
do
{
foreach (var File in FileList)
{
/// Method stops the loop waiting on a local AutoResetEvent
/// if the CompleteSignal returns faster than the
/// desired working rate of ~2 seconds
PauseIfRequired(Stopped);
/// While not 'Stopped', poll for Automatic Mode
/// NOTE: This mimics how the online system polls a digital
/// input instead of a ManualResetEvent.
while (!Stopped.IsCancellationRequested)
{
if (AutoMode.WaitOne(100))
{
/// Class level Field as the Interface did not allow
/// for passing the string with the event below
m_nextFile = File;
// Raises Event async using Task.Factory.StartNew() extension
m_acquireData.Raise();
break;
}
}
// Escape if Canceled
if (Stopped.IsCancellationRequested)
break;
// If In Automatic Mode, Wait for Complete Signal
if (AutoMode.WaitOne(0))
{
// Ensure Signal Transition
CompleteSignal.WaitOne(0);
if (!CompleteSignal.WaitOne(10000))
{
// Log timeout and warn User after 10 seconds, then continue looping
}
}
}
// Keep looping through same set of files until 'Stopped' if in Infinite Replay Mode
} while (!Stopped.IsCancellationRequested && InfiniteReplay);
}
Async घटनाक्रम
नीचे की घटनाओं के लिए विस्तार है और सबसे डिफ़ॉल्ट अतुल्यकालिक विकल्प का उपयोग कर क्रियान्वित कर रहे हैं। 'TryRaising()' एक्सटेंशन केवल प्रतिनिधियों को एक प्रयास में लपेटते हैं और किसी अपवाद को लॉग करते हैं (जबकि वे फिर से फेंक नहीं देते हैं, यह अपवादों को पकड़ने के लिए जिम्मेदार होने के लिए सामान्य कार्यक्रम प्रवाह का हिस्सा नहीं है)।
using System.Threading.Tasks;
using System;
namespace Common.EventDelegates
{
public delegate void TriggerEvent();
public delegate void ValueEvent<T>(T p_value) where T : struct;
public delegate void ReferenceEvent<T>(T p_reference);
public static partial class DelegateExtensions
{
public static void Raise(this TriggerEvent p_response, bool p_synchronized = false)
{
if (p_response == null)
return;
if (!p_synchronized)
Task.Factory.StartNew(() => { p_response.TryRaising(); });
else
p_response.TryRaising();
}
public static void Broadcast<T>(this ValueEvent<T> p_response, T p_value, bool p_synchronized = false)
where T : struct
{
if (p_response == null)
return;
if (!p_synchronized)
Task.Factory.StartNew(() => { p_response.TryBroadcasting(p_value); });
else
p_response.TryBroadcasting(p_value);
}
public static void Send<T>(this ReferenceEvent<T> p_response, T p_reference, bool p_synchronized = false)
where T : class
{
if (p_response == null)
return;
if (!p_synchronized)
Task.Factory.StartNew(() => { p_response.TrySending(p_reference); });
else
p_response.TrySending(p_reference);
}
}
}
जीयूआई सुरक्षित आह्वान
using System;
using System.Windows.Forms;
using Common.FluentValidation;
using Common.Environment;
namespace Common.Extensions
{
public static class InvokeExtensions
{
/// <summary>
/// Execute a method on the control's owning thread.
/// </summary>
/// http://stackoverflow.com/q/714666
public static void SafeInvoke(this Control p_control, Action p_action, bool p_forceSynchronous = false)
{
p_control
.CannotBeNull("p_control");
if (p_control.InvokeRequired)
{
if (p_forceSynchronous)
p_control.Invoke((Action)delegate { SafeInvoke(p_control, p_action, p_forceSynchronous); });
else
p_control.BeginInvoke((Action)delegate { SafeInvoke(p_control, p_action, p_forceSynchronous); });
}
else
{
if (!p_control.IsHandleCreated)
{
// The user is responsible for ensuring that the control has a valid handle
throw
new
InvalidOperationException("SafeInvoke on \"" + p_control.Name + "\" failed because the control had no handle.");
/// jwdebug
/// Only manually create handles when knowingly on the GUI thread
/// Add the line below to generate a handle http://stackoverflow.com/a/3289692/1718702
//var h = this.Handle;
}
if (p_control.IsDisposed)
throw
new
ObjectDisposedException("Control is already disposed.");
p_action.Invoke();
}
}
}
}
Sleep.For()
using System.Threading;
using Common.FluentValidation;
namespace Common.Environment
{
public static partial class Sleep
{
public static bool For(int p_milliseconds, CancellationToken p_cancelToken = default(CancellationToken))
{
// Used as "No-Op" during debug
if (p_milliseconds == 0)
return false;
// Validate
p_milliseconds
.MustBeEqualOrAbove(0, "p_milliseconds");
// Exit immediate if cancelled
if (p_cancelToken != default(CancellationToken))
if (p_cancelToken.IsCancellationRequested)
return true;
var SleepTimer =
new AutoResetEvent(false);
// Cancellation Callback Action
if (p_cancelToken != default(CancellationToken))
p_cancelToken
.Register(() => SleepTimer.Set());
// Block on SleepTimer
var Canceled = SleepTimer.WaitOne(p_milliseconds);
return Canceled;
}
}
}
मैं बस इतना कह सकता हूं कि "शुभकामनाएं" ... यह एक कठिन है, और यह आमतौर पर इस (जटिल) तीसरे पक्ष के लिए इस जटिल में कुछ प्रगति करने के लिए बहुत मुश्किल है। लेकिन फिर मेरे साथी सोर्स कभी मुझे आश्चर्यचकित नहीं करते। – Floris
प्रक्रिया एक्सप्लोरर डाउनलोड करें और अपना ऐप चुनें। फिर व्यू -> लोअर फलक - हैंडल के अंतर्गत चुनें। इससे आपको एक ऐसा विचार मिलना चाहिए जो आप लीक कर रहे हैं (म्यूटेक्स, इवेंट, फाइल, ...) यदि यह नामित म्यूटेक्स या फ़ाइल हैंडल है तो आपको सीधे यह पता लगाने का एक अच्छा मौका होना चाहिए कि समस्याएं कहां से आती हैं। –
@AloisKraus हां, मेरे पास पहले से ही पीई है, बस यह नहीं पता कि इसे पूरी तरह से कैसे उपयोग किया जाए। मैं सूची में शायद 200 हैंडल देख रहा हूं हालांकि मेरी ऐप (बस पुनरारंभ) अभी लगभग 2500 का उपयोग कर रही है। ~ 30 'फ़ाइल' और ~ 40' कुंजी 'जो दोनों स्थिर लगते हैं, लेकिन' थ्रेड 'हैंडल के बहुत सारे हैं जिन्हें बनाया और नष्ट किया जा रहा है (लाल/हरा हाइलाइट जोड़ा और हटा दिया जाता है)। सूची में केवल 4 'घटना' और 6 'उत्परिवर्ती' प्रकार। मैं ज्यादातर आग लगाना और भूलना चाहता हूं, मैं उनका निपटान नहीं करता हूं या आमतौर पर प्रतीक्षा करता हूं। मैं कार्य के अंदर अपवाद पकड़ता हूं, उन्हें लॉग इन करता हूं और फिर वापस लौटता हूं ... कार्य को अपने आप पर स्पिन करने देता हूं। – HodlDwon