Pergunta

Quais são as consequências (positivas/negativas) do uso do inseguro palavra-chave em C# usar ponteiros?Por exemplo, o que acontece com a coleta de lixo, quais são os ganhos/perdas de desempenho, quais são os ganhos/perdas de desempenho em comparação com outras linguagens gerenciamento manual de memória, quais são os perigos, em que situação é realmente justificável fazer uso desta linguagem recurso, é mais longo para compilar ...?

Foi útil?

Solução

Como já mencionado por Conrad, existem algumas situações em que o acesso inseguro à memória em C# é útil.Não há tantos deles, mas existem alguns:

  • Manipulando com Bitmap é quase um exemplo típico em que você precisa de algum desempenho adicional que pode ser obtido usando unsafe.

  • Interoperabilidade com APIs mais antigas (como WinAPI ou DLLs C/C++ nativas) é outra área onde unsafe pode ser bastante útil - por exemplo, você pode querer chamar uma função que recebe/retorna um ponteiro não gerenciado.

Por outro lado, você pode escrever a maioria das coisas usando Marshall aula, que oculta muitas das operações inseguras dentro das chamadas de método.Isso será um pouco mais lento, mas é uma opção se você quiser evitar o uso unsafe (ou se você estiver usando VB.NET que não possui unsafe)

Consequências positivas:Assim, as principais consequências positivas da existência de unsafe em C # é que você pode escrever algum código com mais facilidade (interoperabilidade) e escrever algum código com mais eficiência (manipulando com bitmap ou talvez alguns cálculos numéricos pesados ​​​​usando matrizes - embora não tenha tanta certeza sobre o segundo).

Consequências negativas:Claro, há algum preço que você tem que pagar para usar unsafe:

  • Código não verificável:Código C# escrito usando o unsafe features torna-se não verificável, o que significa que seu código pode comprometer o tempo de execução de alguma forma.Isto não é um grande problema em um confiança total cenário (por ex.aplicativo de desktop irrestrito) - você simplesmente não tem todas as boas garantias do .NET CLR.No entanto, você não pode executar o aplicativo em um ambiente restrito, como hospedagem pública na Web, Silverlight ou confiança parcial (por exemplo,aplicativo em execução na rede).

  • Coletor de lixo também precisa ter cuidado ao usar unsafe.Geralmente, o GC tem permissão para realocar objetos no heap gerenciado (para manter a memória desfragmentada).Quando você aponta um ponteiro para algum objeto, você precisa usar o fixed palavra-chave para informar ao GC que ele não pode mover o objeto até que você termine (o que provavelmente poderia afetar o desempenho da coleta de lixo - mas é claro, dependendo do cenário exato).

Meu palpite é que se o C# não tivesse que interoperar com código mais antigo, provavelmente não suportaria unsafe (e projetos de pesquisa como Singularity, que tentam criar sistemas operacionais mais verificáveis ​​baseados em linguagens gerenciadas, definitivamente não permitem código usnsafe).No entanto, no mundo real, unsafe é útil em alguns casos (raros).

Outras dicas

Eu posso te dar uma situação em que valeu a pena usar:

Eu tenho que gerar um pixel de bitmap por pixel. Drawing.Bitmap.SetPixel() é muito lento. Então eu construo meu próprio gerenciado Array de dados de bitmap e uso unsafe Para obter o IntPtr por Bitmap.Bitmap( Int32, Int32, Int32, PixelFormat, IntPtr).

Para citar o Professional C# 2008:

"Os dois principais motivos para o uso de ponteiros são:

  1. Compatibilidade com versões anteriores - Apesar de todas as instalações fornecidas pelo .NET-Runtime, ainda é possível chamar as funções da API do Windows nativas e, para algumas operações, essa pode ser a única maneira de realizar sua tarefa.Essas funções da API são geralmente escritas em C e geralmente exigem ponteiros como parâmetros.No entanto, em muitos casos, é possível escrever a declaração de Dllimport de uma maneira que evite o uso de ponteiros;Por exemplo, usando a classe System.intptr.
  2. Desempenho - Nas ocasiões em que a velocidade é da maior importância, o ponteiro pode fornecer uma rota para o perfoma otimizado.Se você souber o que está fazendo, pode garantir que os dados sejam acessados ​​ou manipulados da maneira mais eficiente.No entanto, esteja ciente de que, na maioria das vezes, existem outras áreas do seu código nas quais você pode fazer as melhorias de desempenho necessárias sem reairtamento para os ponteiros.Tente usar um Profiler de código para procurar gargalos em seu código - um vem com o Visual Studio 2008 ".

E se você usar ponteiro, seu código exigirá maior nível de confiança para ser executado e se o usuário não conceder, seu código não será executado.

E finalize com uma última citação:

"Aconselhamos fortemente o uso desnecessário de ponteiros, porque não será apenas mais difícil de escrever e depurar, mas também falhará nas verificações de segurança de memória impostas pelo CLR".

A coleta de lixo é ineficiente com objetos de vida longa. O coletor de lixo da .NET funciona melhor quando a maioria dos objetos é lançada rapidamente, e alguns objetos "vivem para sempre". O problema é que os objetos de vida mais longa são liberados apenas durante as coleções completas de lixo, o que incorre em uma penalidade de desempenho significativa. Em essência, objetos de vida longa se movem rapidamente para a geração 2.

(Para mais informações, você pode querer ler sobre o coletor geracional de lixo da .NET: http://msdn.microsoft.com/en-us/library/ms973837.aspx)

Em situações em que objetos, ou uso de memória em geral, terão vida longa, o gerenciamento manual de memória produzirá melhor desempenho, pois pode ser lançado no sistema sem exigir uma coleta completa de lixo.

A implementação de algum tipo de sistema de gerenciamento de memória baseado em uma única matriz grande de bytes, estruturas e muita aritmética do ponteiro, poderia teoricamente aumentar o desempenho em situações em que os dados serão armazenados na RAM por um longo tempo.

Infelizmente, não estou ciente de uma boa maneira de fazer gerenciamento manual de memória no .NET para objetos que terão vida há muito tempo. Isso basicamente significa que os aplicativos que têm dados de vida longa na RAM se tornarão periodicamente sem resposta quando executarem uma coleta completa de lixo de toda a memória.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top