2013-09-06 22 views
8

Bir dizi eşzamanlı bağlantı etkin olduğunda hızlı bir şekilde düşme eğilimi olan bir windows hizmeti ile bir üretim sorununda hata ayıklamaya çalışıyorum. Bir çekirdek dökümü ve DebugDiag büyüsüyle, Preemptive GC devre dışı bırakılmış bir çok iş parçacığı işlerini tamamlayana kadar başlayamayan bekleyen bir GC operasyonu olduğunu anlayabildim. Eğer önleyici GC (konuları 26,27,28,29) ve bir devre dışı olan birkaç konuları görebilirsiniz Yani buradaCLR .tail komutu, önleyici GC'yi devre dışı bırakıyor mu?

26 6e 1444 00..440 8009222 Disabled 00..200:00..f88 00..7a0  0 MTA (Threadpool Completion Port) 
27 c1 1a0c 00..fe0 8009222 Disabled 00..e90:00..f88 00..7a0  0 MTA (Threadpool Completion Port) 
28 b5 17bc 00..6f0 8009222 Disabled 00..268:00..f88 00..7a0  0 MTA (Threadpool Completion Port) 
29 89 1f1c 00..ab0 8009222 Disabled 00..a30:00..f88 00..7a0  0 MTA (Threadpool Completion Port) 
30 ac 2340 00..f70 8009220 Disabled 00..d00:00..d08 00..7a0  1 MTA (GC) (Threadpool Completion Port) 
31 88 1b64 00..fd0 8009220 Enabled 00..b28:00..b48 00..7a0  0 MTA (Threadpool Completion Port) 

(thread: Burada

kusurlu konuları gösteren WinDbg örnek bir iplik çöplük 30) GC'yi gerçekleştirmek için bu ipleri beklemektedir.

Google-fu'm beni benzer bir soruna benzeyen, yalnızca benim durumumda XML içermediğini açıklayan this blog post adresine yönlendiriyor. Ama kazmak için nerede olduğunu bilmek bana yeterli bilgi verdi ve sonunda ben devre önleyici GC ile parçacığı ortak özelliklerinden biri üst bu benzeyen bir yığın izleme olduğunu keşfetti:

ntdll!NtWaitForSingleObject+a 
ntdll!RtlpWaitOnCriticalSection+e8 
ntdll!RtlEnterCriticalSection+d1 
ntdll!RtlpLookupDynamicFunctionEntry+58 
ntdll!RtlLookupFunctionEntry+a3 
clr!JIT_TailCall+db 
... 

DebugDiag da CriticalSection hakkında uyardı ve sadece bu yüzden JIT_TailCall ile ipler RtlEnterCriticalSection

ile de sadece ipler Yani benim soru olduğunu olur: bu kilitlenme neden oluyor .tail talimat aslında var mı? Ve eğer öyleyse: Bu konuda ne yapabilirim?

benim .fsproj dosyaları üzerinde tailcalls devre dışı bırakabilir ancak bunlardan en az biri FSharp.Core.dll geliyor ve decompiler bazı spelunking .tail öğretim varlığını teyit etmek görünüyor gibi görünüyor. Bu yüzden, proje yapılandırmasını değiştirmenin tüm .tail yönergelerini kaldıracağını bilmiyorum.

Daha önce böyle bir şeyle uğraşan var mı?

Güncelleme: Kullanışlı olabilecek daha fazla bilgi. İşte

bu dökümü için !locks çıktısı:

!locks 

CritSec +401680 at 0000000000401680 
WaiterWoken  No 
LockCount   0 
RecursionCount  1 
OwningThread  2340 
EntryCount   0 
ContentionCount bf 
*** Locked 

Scanned 1657 critical sections 

Konu 2340 GC (yukarıda dahil kısmi listede ipliği 30) başlamıştır iplik.

ve !syncblk sadece (başlatılmasını GC tutuyor rahatsız edici ise, kümelerin herhangi dahil değildir), zookeeper bir müşteriye ait olan ürün I tailcalls sorun şüphe

!syncblk 
Index   SyncBlock MonitorHeld Recursion Owning Thread Info   SyncBlock Owner 
11 0000000019721a38   1   1 0000000019766e20 638 7 0000000000fb2950 System.Collections.Generic.LinkedList`1[[ZooKeeperNet.Packet, ZooKeeperNet]] 
    Waiting threads: 
18 0000000019721c68   1   1 000000001ae71420 8ac 13 00000000012defc8 System.Collections.Generic.LinkedList`1[[ZooKeeperNet.Packet, ZooKeeperNet]] 
    Waiting threads: 
----------------------------- 
Total   64 
CCW    0 
RCW    0 
ComClassFactory 0 
Free   5 

cevap

1

gösteren (Aksi takdirde, çok daha fazla sayıda F # kullanıcısı bu soruna çarpabilirdi. Çağrı yığınından, kodunuzun kritik bir bölümde beklemesi gibi görünüyor, bu da sorunun kaynağı olmanın çok daha muhtemel görünüyor ... Kodunuzdaki hangi senkronizasyon ilkellerinin güvenebileceği hakkında bir fikriniz var mı?

+0

Standart .Net Monitor sınıfları, ancak bunların gösterildikleri yığın izleri, kilitleri kullanan birkaç yerim var. bu kodun yakınında. Bu temelde liste işlemedir (bu yüzden List.iter, Map.find, vb.). İlginç olan şey, tüm ipliklerin az ya da çok aynı eylemi gerçekleştirmesidir, ancak 60 ya da daha fazlası aktif bağlantılardır, sadece 6'sı önleyici GC'yi devre dışı bırakmıştır – ckramer

+1

'List.iter (fun _ ->. lock ..) xs 'yığın izlerini sizi 'List.iter' olarak gösterir mi? – t0yv0

+0

Önleyici GC devre dışı bırakılan izlerde hiç kilitleme yok. Aynı zamanda farklı kuyruk optimizasyonlu fonksiyonlarda da meydana gelirler (bir durumda MapTreeInternal.mapi, bir diğeri de Primitives.Basics.List.iter, yine bir başka MapTreeModule.find'tir). Bu çağrıların hepsi de F # kayıt türleri üzerinde çalışıyor. Bu yüzden, burada yönetilmeyen kaynaklardan bahsetmemek için, burada tek kullanımlık örneklerin bile olmadığını söyleyebilirim. Tüm iş parçacıklarının ortak bir özelliği, bir Async TCP alma işlemi aracılığıyla çağrılır. Bunun bir şekilde dahil olup olmadığını bilmiyorum. – ckramer

1

Belki biraz geç ve tarif ettiğin problem, sahip olduğumdan biraz farklı görünüyor olsa da, verdiğiniz arama izi bazı ortak zeminlerin olabileceğini gösteriyor.

my answer'da daha ayrıntılı bilgileri kendi sorumluğumda bulabilirsiniz, ancak kısaca, Windows 7 ve .NET 4.0-4.5'in birleşimi ile birlikte F # problematiğinde kuyruğun tekrarlanmasını sağlar ve aşırı kilitlemeye neden olur. .NET'i 4.6'ya yükseltmek veya Windows 8'e yükseltmek sorunu çözmektedir. Ayrıca, çöp toplama konusunda bir sorunla karşılaştığınız için, server garbage collection'u kullanarak bakmak isteyebilirsiniz. Bu, yukarıdaki sorunu bulmadan önce yaptığım şeylerden biri ve deneyimlediğimiz performans sorunlarının büyük bir bölümünü çözdü. Gerekli olan her şey app.config dosyasında şu şekildedir:

<configuration> 
    ... 
    <runtime> 
    ... 
    <gcServer enabled="true"/> 
    ... 
    </runtime> 
    ... 
</configuration>