Pergunta

Eu não estou fazendo esta pergunta por causa dos méritos de coleta de lixo em primeiro lugar. A minha principal razão para pedir isso é que eu sei que Bjarne Stroustrup disse que C ++ terá um coletor de lixo em algum ponto no tempo.

Com o que disse, por que não ele foi adicionado? Já existem alguns coletores de lixo para C ++. Este é apenas um daqueles "mais fácil dizer do que fazer" coisas do tipo? Ou existem outras razões que não tenha sido adicionado (e não serão adicionadas em C ++ 11)?

ligações cruzadas:

Só para esclarecer, eu entendo as razões por que C ++ não tem um coletor de lixo quando foi criado pela primeira vez. Eu estou perguntando por que o coletor não pode ser adicionado em.

Foi útil?

Solução

coleta de lixo implícita poderia ter sido adicionado, mas ele simplesmente não fazer o corte. Provavelmente devido a não apenas complicações de implementação, mas também devido às pessoas não ser capaz de chegar a um consenso geral rápido o suficiente.

A citação de si mesmo Bjarne Stroustrup:

Eu esperava que um coletor de lixo que pode ser opcionalmente activada seria parte de C ++ 0x, mas houve problemas técnicos suficientes que eu tenho que se contentar com apenas um detalhado especificação de um colector, tal como integra com o resto do linguagem, se fornecido. Conforme o caso com essencialmente toda C ++ 0x apresenta, existe uma execução experimental.

Há uma boa discussão do tema aqui .

Visão geral:

C ++ é muito poderoso e permite fazer quase qualquer coisa. Por esta razão, não empurrar automaticamente muitas coisas sobre você que o desempenho impacto força. A coleta de lixo pode ser facilmente implementado com ponteiros inteligentes (objetos que ponteiros envoltório com uma contagem de referência, que auto excluir-se quando a contagem de referência chega a 0).

C ++ foi construída com os concorrentes em mente que não têm coleta de lixo. A eficiência foi a principal preocupação de que C ++ teve de afastar as críticas de em comparação com C e outros.

Existem 2 tipos de coleta de lixo ...

coleta explícita de lixo:

C ++ 0x terá coleta de lixo através de ponteiros criados com shared_ptr

Se você quiser você pode usá-lo, se você não quer que você não é obrigado a usá-lo.

Atualmente você pode usar boost:. Shared_ptr bem se você não quiser esperar para C ++ 0x

coleta de lixo implícita:

Ele não tem coleta de lixo transparente embora. Será um ponto de foco para o futuro C ++ especificações embora.

Por Tr1 não tem coleta de lixo implícita?

Há um monte de coisas que tr1 de C ++ 0x deveria ter tido, Bjarne Stroustrup em entrevistas anteriores afirmou que tr1 não teve tanto como ele teria gostado.

Outras dicas

Para adicionar ao debate aqui.

Existem problemas com a coleta de lixo conhecido, e compreendê-los ajuda a entender por que não há ninguém em C ++.

1. Desempenho?

A primeira queixa é muitas vezes sobre o desempenho, mas a maioria das pessoas realmente não percebem o que estão falando. Como ilustrado pelo Martin Beckett o problema pode não ser o desempenho per se, mas a previsibilidade do desempenho.

Atualmente 2 famílias de GC que são amplamente utilizados:

  • tipo Mark-e-varrer
  • tipo de contagem de referência

O Mark And Sweep é mais rápido (menos impacto no desempenho geral), mas sofre de uma "congelar o mundo" síndrome: ou seja, quando os GC entra em ação, tudo o resto está parado até que o GC tem feito a sua limpeza. Se você deseja construir um servidor que respostas em poucos milissegundos ... algumas transações não vai viver até suas expectativas:)

O problema da Reference Counting é diferente: de contagem de referência adiciona sobrecarga, especialmente em ambientes multi-threading, porque você precisa ter uma contagem atômica. Além disso, há o problema de ciclos de referência, então você precisa de um algoritmo inteligente para detectar esses ciclos e eliminá-los (geralmente implementar por um "congelamento do mundo" também, embora menos frequente). Em geral, a partir de hoje, este tipo (embora normalmente mais sensíveis ou melhor, congelando com menos frequência) é mais lento do que o Mark And Sweep.

Eu tenho um visto um papel de implementadores Eiffel que estavam tentando implementar um Garbage Collector Reference Counting que teria um desempenho mundial semelhante ao Mark And Sweep sem o aspecto "Freeze The World". É necessário um segmento separado para a GC (típica). O algoritmo foi um pouco assustador (no final), mas o papel feito um bom trabalho de introduzir os conceitos um de cada vez e mostrando a evolução do algoritmo da versão "simples" para o pleno direito. Leitura recomendada se eu pudesse colocar minhas mãos para trás no arquivo PDF ...

2. Recursos aquisição é inicialização

É uma expressão comum no C++ que você vai embrulhar a propriedade dos recursos dentro de um objeto para garantir que eles sejam devidamente liberado. É usado principalmente para a memória, uma vez que não têm coleta de lixo, mas também é útil no entanto para muitas outras situações:

  • fechaduras (multi-thread, identificador de arquivo, ...)
  • conexões (para um banco de dados, outro servidor, ...)

A idéia é controlar adequadamente a vida útil do objeto:

  • deve ser vivo, enquanto você precisar dele
  • deve ser morto quando você está feito com ele

O problema da GC é que se isso ajuda com os antigos e, finalmente, garante que mais tarde ... esta "final" pode não ser suficiente. Se você soltar uma trava, você realmente gostaria que ele seja liberado agora, para que ele não bloquear quaisquer outras chamadas!

Os idiomas com GC tem dois arounds de trabalho:

  • Não uso GC quando alocação de pilha é suficiente: é, normalmente, por questões de desempenho, mas no nosso caso ele realmente ajuda desde o escopo define o tempo de vida
  • construção using ... mas é explícita (fraco) RAII enquanto em C ++ RAII é tão implícita de que o usuário não pode involuntariamente cometer o erro (omitindo a palavra-chave using)

3. Ponteiros inteligentes

Ponteiros inteligentes muitas vezes aparecem como uma bala de prata para a memória alça em C++. Muitas vezes tenho ouvido:. Não precisamos GC afinal de contas, uma vez que temos ponteiros inteligentes

Um não poderia estar mais errado.

ponteiros

inteligentes ajudam: conceitos auto_ptr e uso unique_ptr RAII, extremamente útil certamente. Eles são tão simples que você pode escrevê-los por si mesmo com bastante facilidade.

Quando uma necessidade de participação acionária no entanto, fica mais difícil: você pode compartilhar entre multópicos tiple e há alguns problemas sutis com a manipulação da contagem. Portanto, um vai naturalmente para shared_ptr.

É ótimo, é o que Boost para depois de tudo, mas não é uma bala de prata. Na verdade, o principal problema com shared_ptr é que ele emula um GC implementado por Reference Counting mas você precisa para implementar a detecção ciclo sozinho ... Urg

Claro que há esta coisa weak_ptr, mas eu, infelizmente, já visto vazamentos de memória apesar do uso de shared_ptr por causa desses ciclos ... e quando você está em um ambiente multi-threaded, é extremamente difícil de detectar!

4. Qual é a solução?

Não há bala de prata, mas como sempre, é definitivamente viável. Na ausência de GC uma necessidade de ser claro sobre a propriedade:

  • preferem ter um único proprietário em um determinado momento, se possível
  • Se não, certifique-se de que o seu diagrama de classes não tem qualquer ciclo referentes a propriedade e dividi-las com a aplicação sutil de weak_ptr

Então, na verdade, seria ótimo ter um GC ... no entanto não é questão trivial. E nesse meio tempo, só precisamos arregaçar as mangas.

Que tipo? ela deve ser otimizado para controladores de máquina de lavar roupa embutidos, telefones celulares, estações de trabalho ou supercomputadores?
Deve priorizar resposta gui ou carregamento servidor?
deveria usar muita memória ou lotes de CPU?

C / C ++ é usado em apenas muitas circunstâncias diferentes. I algo suspeito como impulso ponteiros inteligentes será suficiente para a maioria dos usuários

Edit - coletores de lixo automáticas não são tanto um problema de desempenho (você sempre pode comprar mais servidor) é uma questão de desempenho predicatable
. Não sabendo quando a GC vai chute no é como empregar um piloto de linha aérea narcolepsia, na maioria das vezes eles são grandes - mas quando você realmente precisa de resposta

Um dos maiores motivos que C ++ não têm construído em coleta de lixo é que a obtenção de coleta de lixo para jogar bonito com destruidores é muito, muito difícil. Tanto quanto eu sei, ninguém realmente sabe como resolvê-lo completamente ainda. Há um monte de problemas para lidar com:

  • vidas determinísticos de objetos (contagem de referência dá-lhe isso, mas GC não. Embora possa não ser tão grande de um negócio).
  • o que acontece se um destruidor lança quando o objeto está sendo lixo coletado? A maioria das linguagens ignorar essa exceção, já que theres realmente nenhuma catch bloco para ser capaz de transportá-lo, mas isso provavelmente não é uma solução aceitável para C ++.
  • Como ativar / desativar isso? Naturalmente provavelmente seria uma decisão tempo, mas o código que é escrito para GC vs código que é escrito para NÃO GC vai ser muito diferente e provavelmente incompatível compilação. Como você concilia isso?

Estes são apenas alguns dos problemas enfrentados.

Embora este seja um velho questão, ainda há um problema que eu não vejo ninguém ter dirigido a todos:. Coleta de lixo é quase impossível especificar

Em particular, o C ++ padrão é bastante cuidado para especificar o idioma em termos de comportamento observável externamente, em vez de como a implementação atinge esse comportamento. No caso da coleta de lixo, no entanto, há é comportamento praticamente não observável externamente.

O idéia geral de coleta de lixo é que ele deve fazer uma tentativa razoável a assegurar que uma alocação de memória terá sucesso. Infelizmente, é essencialmente impossível garantir que qualquer alocação de memória terá sucesso, mesmo se você tem um coletor de lixo em operação. Isso é verdade até certo ponto, em qualquer caso, mas particularmente assim no caso do C ++, porque é (provavelmente) não é possível usar um coletor de cópia (ou algo similar) que se move objetos na memória durante um ciclo de recolha.

Se você não pode mover objetos, você não pode criar um único espaço, contíguo memória em que pretende fazer suas atribuições - e isso significa sua pilha (ou loja livre, ou o que você preferir chamá-lo) pode, e provavelmente, tornar-se fragmentado ao longo do tempo. Este, por sua vez, pode impedir uma atribuição de ter sucesso, mesmo quando não há mais memória livre do que a quantidade que está sendo solicitado.

Embora possa ser possível chegar a alguns garantia de que diz (em essência) que se você repetir exatamente o mesmo padrão de alocação repetidamente, e ele conseguiu pela primeira vez, ele vai continuar a ter sucesso em iterações subseqüentes, desde que a memória alocada tornou-se inacessível entre as iterações. Isso é uma garantia tão fraca que é essencialmente inútil, mas eu não consigo ver nenhuma esperança razoável de fortalecê-lo.

Mesmo assim, é mais forte do que o que foi proposto para C ++. A anterior proposta [aviso: PDF] (que tem caído) não garantia nada. Em 28 páginas da proposta, o que você tem na maneira de comportamento observável externamente foi um único (não-normativa) nota dizendo:

[Observação: Para programas de lixo coletado, uma alta qualidade hospedado implementação deve tentar maximizar a quantidade de memória inacessível ele recupera. -end nota]

Pelo menos para mim, isso levanta uma questão grave sobre o retorno sobre o investimento. Vamos quebrar o código existente (ninguém tem certeza exatamente quanto, mas definitivamente um pouco), colocar novas exigências sobre implementações e novas restrições ao código, e o que recebe em troca é muito possivelmente nada?

Mesmo na melhor das hipóteses, o que temos são os programas que, com base em testes com Java , provavelmente necessitará de cerca de seis vezes mais memória para rodar na mesma velocidade que eles fazem agora. Pior, a coleta de lixo era parte de Java desde o início - lugares C ++ bastante mais restrições sobre o coletor de lixo que ele irá quase certamente ter um mesmo pior relação custo / benefício (mesmo que ir além do que o proposta garantido e assumir que haveria algum benefício).

Eu resumir a situação matematicamente: esta uma situação complexa. Como qualquer matemático sabe, um número complexo tem duas partes: reais e imaginários. Parece-me que o que temos aqui são custos que são reais, mas os benefícios que são (pelo menos a maioria) imaginária.

Se você quiser coleta de lixo automática, há boa comercial e coletores de lixo de domínio público para C ++. Para aplicações onde recolha de lixo é adequado, C ++ é um excelente lixo recolhido linguagem com um desempenho que compara favoravelmente com outros tipos de lixo línguas coletados. Consulte O C ++ Programming Language (4ª Edition) para uma discussão sobre a coleta de lixo automática em C ++. Veja também, Hans-J. para C e C ++ coleta de lixo ( arquivo ).

Além disso, suporta C ++ técnicas de programação que permitem memória gestão para ser seguro e implícita sem coletor de lixo. Considero coleta de lixo uma última escolha e uma maneira imperfeita de manipulação para a gestão de recursos. Isso não significa que nunca é útil, basta que existem melhores abordagens em muitas situações.

Fonte: http://www.stroustrup.com/bs_faq.html#garbage -collection

Quanto ao porquê de ele não tê-lo construído em, Se bem me lembro que foi inventado antes de GC foi a coisa , e eu não acredito que a linguagem poderia ter tido GC por várias razões (IE Backwards compatibilidade com C)

Espero que isso ajude.

Stroustrup fez alguns bons comentários sobre isso em 2013 Indo conferência nativo.

Apenas pular para cerca de 25m50s na este vídeo . (Eu recomendo assistir o vídeo inteiro, na verdade, mas isso salta para o material sobre coleta de lixo.)

Quando você tem realmente um grande linguagem que torna mais fácil (e seguro e previsível e fácil de ler, e fácil de ensinar) para lidar com objetos e valores de forma direta, evitando (explícito) uso da pilha, então você nem deseja coleta de lixo.

Com C ++ moderno, e as coisas que temos em C ++ 11, a coleta de lixo não está mais desejável é, exceto em circunstâncias limitadas. Na verdade, mesmo se um coletor de lixo bom é construído em uma das principais compiladores C ++, eu acho que ele não vai ser usada com muita frequência. Será mais fácil , não mais, para evitar o GC.

Ele mostra este exemplo:

void f(int n, int x) {
    Gadget *p = new Gadget{n};
    if(x<100) throw SomeException{};
    if(x<200) return;
    delete p;
}

Esta é inseguro em C ++. Mas também é inseguro em Java! Em C ++, se a função retorna cedo, o delete nunca será chamado. Mas se você tivesse coleta de lixo completa, como em Java, você simplesmente obter uma sugestão de que o objeto será destruído "em algum momento no futuro" ( Atualização:. é ainda pior que este Java faz não prometem chamar o finalizador de sempre - ele talvez nunca seja chamado). Isso não é bom o suficiente se Gadget possui um identificador de arquivo aberto, ou uma conexão a um banco de dados, ou dados que você buffer de gravação para um banco de dados em um momento posterior. Queremos que o Gadget para ser destruído assim que ele for concluído, a fim de liberar estes recursos o mais rápido possível. Você não quer que seu servidor de banco de dados lutando com milhares de conexões de banco de dados que não são mais necessários -. Ele não sabe que o seu programa é Término

Então, qual é a solução? Existem algumas abordagens. A abordagem óbvia, o que você vai usar para a grande maioria de seus objetos é:

void f(int n, int x) {
    Gadget p = {n};  // Just leave it on the stack (where it belongs!)
    if(x<100) throw SomeException{};
    if(x<200) return;
}

Isso leva menos caracteres de tipo. Ele não tem new ficando no caminho. Ele não requer que você digite Gadget duas vezes. O objecto é destruído no final da função. Se é isso que você quer, isso é muito intuitivo. Gadgets comportam da mesma como int ou double. Previsível, fácil de ler, fácil de ensinar. Tudo é um 'valor'. Às vezes, um grande valor, mas valores são mais fáceis de ensinar, porque você não tem essa 'ação à distância' coisa que você começa com ponteiros (ou referências).

A maioria dos objetos que você faz são para uso somente na função que os criou, e talvez passados ??como entradas para funções criança. O programador não deveria ter que pensar sobre o 'gerenciamento de memória' ao retornar objetos, ou não compartilhar objetos em partes amplamente separadas do software.

Escopo e tempo de vida são importantes. Na maioria das vezes, é mais fácil se o tempo de vida é o mesmo que o escopo. É mais fácil de entender e fácil de ensinar. Quando você quer uma vida diferente, deveria ser óbvio lendo o código que você está fazendo isso, pelo uso de shared_ptr por exemplo. (Ou retornar (grande) objetos de valor, aproveitando mover-semântica ou unique_ptr.

Isto pode parecer um problema de eficiência. E se eu quiser retornar um Gadget do foo()? C ++ 11 de semântica movimento tornar mais fácil para retornar objetos grandes. Basta escrever Gadget foo() { ... } e ele vai trabalhar, e trabalhar rapidamente. Você não precisa mexer com && mesmo, basta retornar coisas por valor e da língua, muitas vezes, ser capaz de fazer as otimizações necessárias. (Mesmo antes C ++ 03, compiladores fez um notavelmente bom trabalho a evitar cópias desnecessárias.)

Como Stroustrup disse em outras partes do vídeo (parafraseando): "Apenas um computadorcientista insistiria em copiar um objeto, e depois destruir o original. (Platéia ri). Porque não basta mover o objeto diretamente para o novo local? Isto é o que os seres humanos (e não cientistas da computação) esperam. "

Quando você pode garantir é necessária apenas uma cópia de um objeto, é muito mais fácil de entender a vida útil do objeto. Você pode escolher o que a política de vida que você quer, e coleta de lixo está lá, se quiser. Mas quando você entender os benefícios das outras abordagens, você verá que a coleta de lixo é na parte inferior da sua lista de preferências.

Se isso não funcionar para você, você pode usar unique_ptr, ou na sua falta, shared_ptr. Bem escrito C ++ 11 é mais curto e mais fácil de ler, e mais fácil de ensinar do que muitas outras línguas quando se trata de gerenciamento de memória.

A idéia por trás C ++ foi que você não iria pagar qualquer impacto no desempenho para os recursos que você não usa. Assim, adicionando coleta de lixo teria significado ter alguns programas correr em linha reta sobre o hardware do caminho C faz e alguns dentro de algum tipo de máquina virtual em tempo de execução.

Nada impede que você use alguma forma de ponteiros inteligentes que estão vinculados a algum mecanismo de coleta de lixo de terceiros. Se bem me lembro Microsoft está fazendo algo parecido com COM e não ir para o bem.

Para responder a maioria das perguntas "porquê" sobre C ++, leia Projeto e evolução do C ++

Porque C ++ moderno não precisa de coleta de lixo.

FAQ de Bjarne Stroustrup resposta sobre este assunto diz :

Eu não gosto de lixo. Eu não gosto de jogar lixo. Meu ideal é eliminar a necessidade de um coletor de lixo por não produzir qualquer lixo. Isso agora é possível.


A situação, por código escrito nos dias de hoje (C ++ 17 e seguindo o oficial Diretrizes núcleo ) é a seguinte:

  • código relacionado a propriedade mais memória está em bibliotecas (especialmente aqueles recipientes fornecendo).
  • A maioria uso do código envolvendo a posse de memória segue o RAII padrão , então alocação é feita em construção e desalocação na destruição, o que acontece quando sair do âmbito em que algo foi alocado.
  • Você não alocar explicitamente ou desalocar memória diretamente .
  • Raw ponteiros não possuem de memória ( Se você seguiu as diretrizes), então você não pode vazar, passando-os ao redor.
  • Se você está se perguntando como você está indo para passar os endereços a partir de sequências de valores na memória - você vai estar fazendo isso com um período ; nenhum ponteiro raw necessário.
  • Se você realmente precisa de um "ponteiro" possuir, você usa C ++' ponteiros inteligentes padrão da biblioteca - eles não podem vazar, e são bastante eficientes. Alternativamente, você pode passar a propriedade através de limites de alcance com "ponteiros proprietário" . Estes são incomuns e devem ser utilizados de forma explícita; e eles permitem estática parcial verificando contra vazamentos.

"Ah, é? Mas o que dizer ...

... se eu escrever o código da maneira que costumava escrever C ++ nos velhos tempos? "

Na verdade, você poderia apenas ignorar todas as diretrizes e escrever o código do aplicativo com vazamento -. E ele irá compilar e executar (e vazamento), mesmo de sempre

Mas não é um "simplesmente não fazer isso" a situação, onde se espera que o desenvolvedor para ser virtuoso e exercer um monte de auto-controle; não é apenas mais simples de escrever código de não-conformidade, nem é mais rápido para escrever, nem é melhor desempenho. Aos poucos, ele também se tornará mais difícil de escrever, como você teria de enfrentar uma crescente "diferença de impedância" com o código de conformidade oferece e espera.

... se eu reintrepret_cast? Ou fazer aritmética de ponteiro? Ou outros tais hacks? "

Na verdade, se você colocar sua mente para ela, você pode escrever código que mexe as coisas Apesar de jogar agradável com as orientações. Mas:

  1. Você faria isso raramente (em termos de lugares no código, não necessariamente em termos de fração de tempo de execução)
  2. Você só faria isso intencionalmente, não por acaso.
  3. Se o fizer, vai se destacar em uma base de código em conformidade com as diretrizes.
  4. É o tipo de código em que você faria desvio da GC em uma outra língua de qualquer maneira.

... desenvolvimento da biblioteca? "

Se você é um desenvolvedor C ++ biblioteca, então você faz código inseguro gravação envolvendo ponteiros crus, e você é obrigado a código com cuidado e responsabilidade - mas estes são peças independentes de código escritos por especialistas (umd mais importante, revisados ??por especialistas).


Então, é como Bjarne disse: Não há realmente nenhuma motivação para coleta de lixo em geral, como tudo que você, mas certifique-se para não produzir lixo. GC está se tornando um não-problema com C ++.

Isso não quer dizer GC não é um problema interessante para certas aplicações específicas, quando você quer estratégias de alocação de costume empregar e de-alocações. Para aqueles que você gostaria de alocação personalizado e de alocação de, não um GC-nível de linguagem.

Um dos princípios fundamentais por trás da linguagem C originais é que a memória é composta por uma sequência de bytes e código precisa apenas se preocupam com o que os bytes média no exato momento em que eles estão sendo usados. Modern C permite compiladores de impor restrições adicionais, mas inclui C - C ++ e retém - a capacidade de se decompor um ponteiro para uma sequência de bytes, montar qualquer sequência de bytes que contêm os mesmos valores em um ponteiro, e, em seguida, usar esse ponteiro para acessar o objeto anteriormente.

Enquanto que a capacidade pode ser útil - ou mesmo indispensável - em alguns tipos de aplicações, uma linguagem que inclui essa capacidade será muito limitado em sua capacidade de suportar qualquer tipo de coleta de lixo útil e confiável. Se um compilador não sabe tudo o que foi feito com os bits que compõem um ponteiro, ele não terá como saber se informações suficientes para reconstruir o ponteiro pode existir em algum lugar no universo. Uma vez que seria possível para que a informação seja armazenada de forma que o computador não seria capaz de acesso mesmo que sabia sobre eles (por exemplo, os bytes que compõem o indicador poderia ter sido mostrado na tela o tempo suficiente para alguém para escrever -los para baixo em um pedaço de papel), pode ser literalmente impossível para um computador para saber se um ponteiro poderia ser usado no futuro.

Uma peculiaridade interessante de muitas estruturas recolhidas-lixo é que uma referência de objeto não definido pelos padrões de bit neles contidos, mas pela relação entre os bits realizada na referência de objecto e outra informação realizada noutro local. Em C e C ++, se o padrão de bits armazenados em um ponteiro identifica um objecto, que vai identificar o padrão de bits que objecto até que o objecto é destruído explicitamente. Em um sistema de GC típico, um objecto pode ser representado por um padrão de bits 0x1234ABCD em um momento no tempo, mas o próximo ciclo de GC pode substituir todas as referências a 0x1234ABCD com referências a 0x4321BABE, após o que o objecto seria representada pelo último padrão. Mesmo se fosse para exibir o padrão de bits associados com uma referência de objecto e, em seguida, depois lê-lo de volta a partir do teclado, não haveria nenhuma expectativa de que o mesmo padrão de bits poderiam ser utilizados para identificar o mesmo objecto (ou qualquer objecto).

Toda a conversa técnica é complicar o conceito.

Se você colocar GC em C ++ para toda a memória automaticamente, em seguida, considerar algo como um navegador web. O navegador deve carregar um documento web completo e scripts web executados. Você pode armazenar variáveis ??de script web na árvore do documento. Em um documento grande em um navegador com muitas abas abertas, isso significa que cada vez que a GC deve fazer uma coleção cheia também deve verificar todos os elementos do documento.

Na maioria dos computadores Isto significa que falhas de página ocorrerão. Portanto, a razão principal, para responder à pergunta é que falhas de página irá ocorrer. Você vai saber isso como quando seu PC começa a fazer um monte de acesso ao disco. Isso ocorre porque o GC deve tocar muita memória a fim de provar ponteiros inválidos. Quando você tem um aplicativo bona fide usando muita memória, ter que varrer todos os objetos cada coleção é estragos por causa das falhas de página. Uma falha de página é quando as necessidades de memória virtual para voltar lido na RAM do disco.

Assim, a solução correta é dividir uma aplicação para as peças que precisam GC e as partes que não. No caso do exemplo navegador web acima, se a árvore documento foi alocada com malloc, mas a RAN javascript com GC, em seguida, cada vez que o GC chutes nele apenas verifica uma pequena parte da memória e todos os elementos paginada da memória para a árvore documento não precisa voltar paginado em.

Para entender melhor este problema, procure na memória virtual e como ele é implementado em computadores. É tudo sobre o fato de que 2 GB está disponível para o programa quando não há realmente que muito RAM. Em computadores modernos com 2 GB de RAM para um sistema de 32 bits não é um problema desde que apenas um programa está em execução.

Como um exemplo adicional, considere uma coleção completa que deve traçar todos os objetos. Primeiro você deve verificar todos os objetos acessíveis via raízes. Segundo verificar todos os objetos visíveis no passo 1. destruidores de espera Depois de digitalização. Então vá para todas as páginas novamente e desligue todos os objetos invisíveis. Isto significa que muitas páginas podem ficar trocados fora e para trás várias vezes.

Assim, a minha resposta para trazê-lo curta é que o número de falhas de página que ocorrem como resultado de tocar toda a memória faz com que completa GC para todos os objetos em um programa a ser inviável e assim o programador deve ver GC como um auxílio para coisas como scripts e trabalho de banco de dados, mas fazer coisas normais com o gerenciamento de memória manual.

E a outra razão muito importante, claro, é variáveis ??globais. Para que o coletor de saber que um ponteiro variável global está no GC isso exigiria palavras-chave específicas e, portanto, existente código C ++ não iria funcionar.

resposta curta: Nós não sabemos como fazer a coleta de lixo eficiente (com menor tempo e sobrecarga de espaço) e corretamente o tempo todo (em todos os casos possíveis).

resposta longa: Assim como C, C ++ é uma linguagem de sistemas; Isto significa que é usado quando você está escrevendo código do sistema, por exemplo, sistema operacional,. Em outras palavras, C ++ é projetado, assim como C, com a melhor possível desempenho como o principal alvo. padrão da língua' não vai acrescentar qualquer recurso que possa dificultar o objectivo de desempenho.

Esta pausa a pergunta: Por que o desempenho de coleta de lixo atrapalha? A principal razão é que, quando se trata de implementação, nós [cientistas da computação] não sei como fazer a coleta de lixo com sobrecarga mínima, para todos os casos. Por isso, é impossível para o sistema compilador C ++ e tempo de execução para executar a coleta de lixo eficiente o tempo todo. Por outro lado, um programador C ++, deve conhecer a sua concepção / implementação e ele é a melhor pessoa para decidir a melhor forma de fazer a coleta de lixo.

Por último, se o controle (hardware, detalhes, etc.) e desempenho (tempo, espaço, energia, etc.) não são os principais constrangimentos, em seguida, C ++ não é a ferramenta de gravação. Outra língua poderia atender melhor e oferecer uma gestão mais [escondido] tempo de execução, com a sobrecarga necessário.

Quando você compara C ++ com Java, você pode ver imediatamente que C ++ não foi projetado com lixo implícita coleção em mente, enquanto que Java foi.

Tendo coisas como ponteiros arbitrários em C-Style e destruidores deterministas que não só retardam o desempenho de GC-implementações, seria também destruir compatibilidade com versões anteriores para uma grande quantidade de C ++ -. Legado-code

Além disso, C ++ é uma linguagem que se destina a executar como autônomo executável em vez de ter um ambiente de tempo de execução complexa.

Todos em todos: Sim, seria possível adicionar coleta de lixo para C ++, mas por uma questão de continuidade, é melhor não fazê-lo. O custo de fazê-lo seria maior do que o benefício.

Principalmente por dois motivos:

  1. Porque ele não precisa de um (IMHO)
  2. Porque é praticamente incompatível com RAII, que é a pedra angular de C ++

C ++ já oferece gerenciamento de memória manual, alocação de pilha, RAII, recipientes, ponteiros automáticas, ponteiros inteligentes ... Isso deve ser suficiente. coletores de lixo são para programadores preguiçosos que não querem gastar 5 minutos pensando sobre quem deve possuir quais objetos ou quando deve ser liberado recursos. Não é assim que fazemos as coisas em C ++.

coleta de lixo imponente é realmente um nível baixo para mudança de paradigma de alto nível.

Se você olhar para a forma como cordas são tratadas em uma linguagem com coleta de lixo, você vai descobrir que eles só permitem funções de manipulação de seqüência de alto nível e não permitem o acesso binário para as cordas. Simplificando, todas as funções de cordas verifique primeiro os ponteiros para ver onde a corda é que, mesmo se você está apenas tirando um byte. Então, se você está fazendo um loop que processa cada byte em uma seqüência em uma linguagem com coleta de lixo, ele deve calcular a base localização mais offset para cada iteração, porque ele não pode saber quando a corda se moveu. Então você tem que pensar em montes, pilhas, fios, etc etc.

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