2014-05-06 22 views
8

Ho un'applicazione C# che dipende da un assembly non gestito di terze parti per accedere a determinati componenti hardware.che si occupa di una dll non gestita con una perdita di memoria

Il codice non gestito presenta una perdita di memoria che aumenterà il consumo di memoria di ~ 10mb dopo ogni accesso. Il problema è noto; nessun bugfix è disponibile.

C'è un modo per continuare a utilizzare questo assembly senza riavvii regolari?

Ho provato a creare un AppDomain separato, caricare il codice in questione in quell'AppDomain tramite appDomain.CreateInstanceAndUnwrap() e successivamente lo scarico del dominio tramite AppDomain.Unload(). Tuttavia, questo a quanto pare non libera la memoria non gestita utilizzata da quel dominio, ma solo la memoria gestita.

Potrei anche dividere l'applicazione in due parti indipendenti e riavviare solo la parte con la dll non gestita. Tuttavia, ciò significherebbe una riprogettazione importante e probabilmente causerebbe un grande rallentamento, poiché sarebbe necessario scambiare grandi quantità di dati tra queste due parti.

C'è un altro modo per domare questo assembly che perde e costringerlo a rilasciare la sua memoria senza riavviare.?

+3

A meno che non sia possibile scavare forzatamente nelle strutture dati utilizzate dalla dll e liberare manualmente la memoria trapelata, quindi no. Il processo separato è il meglio che puoi fare. Non era del tutto chiaro nella tua domanda, ma avendo un processo separato in vita per un po ', gestendo più richieste fino a diventare "troppo grande" (qualunque sia lo standard che scegli), e poi girandolo di nuovo, non avresti * che * molto rallentamento, ma alcuni, sì. Potresti, ad esempio, crearne uno nuovo e continuare a pompare le richieste a quello vecchio finché il nuovo non fosse pronto a prendere il sopravvento, evitando i tempi di fermo. –

+0

@ LasseV.Karlsen - conisder copia-incolla come risposta. Non penso ci sia altro da dire qui. –

+0

Penso che la cosa migliore da fare sia dividere l'applicazione. È possibile evitare alcuni rallentamenti utilizzando la memoria condivisa per spostare grandi quantità di dati. Un'alternativa sarebbe quella di agganciare 'malloc' /' free' (o 'new' /' delete') per la libreria e implementare il proprio heap separato per la DLL. A seconda che la DLL usi un runtime C/C++ dinamico o uno statico, questo varierà da estremamente complicato a disperatamente complicato. –

risposta

4

Il modo in cui lo descrivi, la DLL sta allocando memoria non gestita. Questo tipo di memoria non sarà influenzato dall'atto di scaricare un appdomain, sfortunatamente, come hai già scoperto.

Hai un paio di opzioni, ma non credo che nessuno di loro si appellano:

  1. È possibile continuare a utilizzare la dll nella vostra applicazione principale. È possibile consigliare ai propri utenti/clienti di disporre di molta memoria disponibile, ma è necessario riavviare l'applicazione di volta in volta. Probabilmente vorresti rilevare condizioni di memoria insufficiente prima che il programma inizi effettivamente a bloccarsi, per spingere gentilmente l'utente a riavviarlo, invece di fare un crash con un'eccezione.
  2. Si può provare a scavare nelle strutture dati della DLL. Se la dll sta effettivamente cambiando (ad esempio, le nuove versioni stanno uscendo), vorrei fortemente suggerire di appoggiarsi sull'autore per ottenere la perdita di memoria riparata. Tuttavia, questo sembra improbabile dal momento che sono abbastanza sicuro che la perdita sarebbe riparata se una nuova versione è uscito. Come tale, legare il codice direttamente alle interiora di questa DLL potrebbe essere una soluzione a. Avere accesso al puntatore effettivo che fa riferimento alla memoria non gestita potrebbe consentire di liberarlo manualmente come meglio credi.
  3. È possibile isolare il problema in un processo separato. Maggiori informazioni su quello sotto.
  4. È possibile reimplementare la funzionalità della DLL.

Ci potrebbe essere una quinta o una sesta opzione qui, ma pensate che il precedente 4 copra le cose che mi sono venute fuori dalla cima della mia testa.

Chi isolandola in un processo separato, ecco cosa vorrei provare a fare prima:

vorrei girare un processo, e le richieste di pompa ad esso utilizzando il canale più veloce la comunicazione intra-processo si possono trovare. I tubi sembrano un buon adattamento, o file mappati in memoria.

In questo processo separato, è possibile rilevare la condizione di esaurimento della memoria, si spera un po 'prima, in modo da poter consigliare al programma principale che dovrebbe pensare di avviare un processo di sostituzione.

Il processo principale poteva farlo, ma invece di aspettare che quell'altro processo si verificasse completamente, poteva continuare a pompare qualche altra richiesta all'istanza di prossima istanza, riempiendola un po 'di più , prima di passare alla nuova istanza e chiedere al vecchio di terminare.

Ciò ridurrebbe al minimo i tempi di inattività a spese di avere temporaneamente un processo in più durante le transizioni.

Tutto ciò dipende, molto, dagli scenari reali che si hanno. Se è necessario chiamare questa dll 100 o 1000 di volte al secondo, la comunicazione intra-processo potrebbe non essere possibile in ogni caso.

1

La DLL alloca memoria non gestita nel processo e non la libera. Lo scaricamento del dominio dell'applicazione ovviamente non sarà di aiuto in questo caso perché la memoria è allocata all'interno del processo, non all'interno del dominio dell'applicazione.

Per eliminare la perdita di memoria è necessario liberare la memoria non condivisa e ci sono due modi per farlo: terminare il processo e lasciare che sia il sistema operativo a farlo o liberarlo da soli. Per liberare se stessi, è necessario acquisire l'handle nella memoria sia recuperandolo tramite l'interfaccia pubblica della DLL, dai dettagli di implementazione privata della DLL o esaminando l'heap del processo. Probabilmente è fattibile, ma immagino che non sarà né divertente, né facile e forse nemmeno robusto.

In confronto la soluzione con due processi e il riavvio regolare della perdita sembra facile e robusta. Non mi preoccuperei delle prestazioni perché è possibile ad esempio utilizzare memory mapped files per condividere i dati ed evitare di copiarli.

La soluzione più semplice sarebbe naturalmente quella di risolvere la perdita di memoria o addirittura di risolverla manualmente risolvendo l'origine, se disponibile, o correggendo la DLL.