Pergunta

Digamos que você queira escrever um método de alto desempenho que processe um grande conjunto de dados. Por que os desenvolvedores não deveriam ter a capacidade de ativar o gerenciamento manual de memória em vez de serem forçados a se mudar para C ou C ++?

void Process()
{
    unmanaged
    {
        Byte[] buffer;
        while (true)
        {
            buffer = new Byte[1024000000];

            // process

            delete buffer;
        } 
    }   
}
Foi útil?

Solução

Porque permitir que você exclua manualmente um bloco de memória, enquanto ainda pode haver referências a ele (e o tempo de execução não tem como saber que sem fazer um ciclo GC) pode produzir indicadores pendentes e, assim, quebrar Segurança da memória. Os idiomas GC geralmente são seguros de memória por design.

Dito isto, em C#, em particular, você já pode fazer o que quiser:

void Process()
{
    unsafe
    {
        byte* buffer;
        while (true)
        {
            buffer = Marshal.AllocHGlobal(1024000000);

            // process

            Marshal.FreeHGlobal(buffer);
        } 
    }   
}

Observe que, como em c/c ++, você tem aritmética de ponteiro completo para tipos de ponteiro bruto em C# - então buffer[i] ou buffer+i são expressões válidas.

Outras dicas

Se você precisar de alto desempenho e controle detalhado, talvez deva escrever o que está fazendo em C ou C ++. Nem todas as línguas são boas para todas as coisas.

Editado para adicionar: Um único idioma não será bom para todas as coisas. Se você adicionar todos os recursos úteis em todas as boas linguagens de programação, você terá uma bagunça muito grande, muito pior que o C ++, mesmo que você possa evitar inconsistência.

Os recursos não são gratuitos. Se um idioma tiver um recurso, é provável que as pessoas o usem. Você não poderá aprender C# bem o suficiente sem aprender as novas rotinas de gerenciamento de memória manual C#. As equipes do compilador vão implementá -lo, com o custo de outros recursos do compilador que são úteis. É provável que o idioma se torne difícil analisar como C ou C ++, e isso leva a uma compilação lenta. (Como um cara C ++, sempre fico impressionado quando compilo um de nossos projetos C#. A compilação parece quase instantânea.)

Apresenta conflitos entre si, às vezes de maneiras inesperadas. O C90 não pode se sair tão bem quanto a Fortran nos cálculos da matriz, uma vez que a possibilidade de os ponteiros de C são aliases, impede algumas otimizações. Se você permitir a aritmética do ponteiro em um idioma, precisará aceitar suas consequências.

Você está sugerindo uma extensão C# para permitir gerenciamento manual de memória e, em alguns casos, seria útil. Isso significaria que a memória teria que ser alocada de maneiras separadas, e teria que haver uma maneira de dizer à memória gerenciada manualmente da memória gerenciada automaticamente. De repente, você complicou o gerenciamento de memória, há mais chance de um programador estragar tudo e o próprio gerenciador de memória é mais complicado. Você está ganhando um pouco de desempenho que importa em alguns casos em troca de mais complicações e gerenciamento de memória mais lento em todos os casos.

Pode ser que, em algum momento, tenhamos uma linguagem de programação que seja boa para quase todos os propósitos, desde scripts até trituração de números, mas não há nada de popular que esteja perto disso. Enquanto isso, precisamos estar dispostos a aceitar as limitações de usar apenas um idioma ou o desafio de aprender vários e alternar entre eles.

No exemplo que você postou, por que não apagar o buffer e reutilizá-lo?

O coletor de lixo .NET é muito bom em descobrir quais objetos não são mais referenciados e liberando a memória associada em tempo hábil. De fato, o coletor de lixo possui uma pilha especial (o grande heap de objeto), no qual coloca objetos grandes como esse, que é otimizado para lidar com eles.

Além disso, não permitir que as referências sejam explicitamente liberadas, simplesmente remove toda uma série de bugs com vazamentos de memória e ponteiros pendurados, o que leva a um código muito mais seguro.

Liberar cada bloco não utilizado individualmente, como feito em um idioma com gerenciamento explícito de memória, pode ser mais caro do que deixar um coletor de lixo fazê -lo, porque o GC tem a possibilidade de usar esquemas de cópia para gastar um tempo linear ao número de blocos deixados vivos (ou o número de blocos recentes deixados vivos) em vez de ter que lidar com cada bloco morto.

A mesma razão pela qual a maioria dos kernels não permite que você agende seus próprios tópicos. Porque 99,99+% do tempo você realmente não precisa, e expor essa funcionalidade O resto do tempo só tentará você a fazer algo potencialmente estúpido/perigoso.

Se você realmente precisa de controle de memória de grãos finos, escreva essa seção de código em outra coisa.

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