O gerenciamento de memória na programação está se tornando uma preocupação irrelevante?
Gerenciamento de memória (ou controle) é realmente o principal motivo pelo qual estou usando C e C ++.
A memória é comparativamente barata agora.
Memória não rápida. Ainda estamos analisando um pequeno número de registros, algo como cache de dados de 32 KB para L1 no i7, 256 KB para L2 e 2 MB para L3 / core. Dito isto:
Se não falamos em termos de plataformas de destino com limites estritos de memória de trabalho (isto é, sistemas embarcados e similares), o uso de memória deve ser uma preocupação ao escolher hoje uma linguagem de uso geral?
Uso de memória em um nível geral, talvez não. Sou um pouco impraticável, pois não gosto da idéia de um bloco de notas que consiga, digamos, 50 megabytes de DRAM e centenas de megabytes de espaço em disco rígido, mesmo que eu tenha isso para poupar e abundar mais. Eu já estou aqui há muito tempo e me parece estranho e meio nojento ver um aplicativo tão simples consumir tanta memória quanto o que deveria ser possível com kilobytes. Dito isto, talvez eu consiga viver comigo mesmo se encontrar algo assim, se ainda for agradável e receptivo.
A razão pela qual o gerenciamento de memória é importante para mim no meu campo é não reduzir tanto o uso de memória em geral. Centenas de megabytes de uso de memória não necessariamente diminuem a velocidade do aplicativo de forma não trivial se nada for acessado com frequência (por exemplo, apenas com o clique de um botão ou outra forma de entrada do usuário, que é extremamente pouco frequente, a menos que você estão falando de jogadores coreanos de Starcraft que podem clicar em um botão um milhão de vezes por segundo).
A razão pela qual é importante no meu campo é manter a memória estreita e próxima, que é acessada com muita frequência (por exemplo, sendo repetida em cada quadro) nesses caminhos críticos. Não queremos que o cache seja perdido toda vez que acessamos apenas um dentre um milhão de elementos que precisam ser acessados em loop a cada quadro. Quando movemos a memória para baixo na hierarquia da memória lenta para a memória rápida em grandes blocos, digamos linhas de cache de 64 bytes, é realmente útil que esses 64 bytes contenham dados relevantes, se podemos encaixar vários elementos de valor nesses 64 bytes e se nossos padrões de acesso são tais que usamos tudo antes dos dados serem despejados.
Esses dados acessados com freqüência para os milhões de elementos podem abranger apenas 20 megabytes, mesmo que tenhamos gigabytes. Ele ainda faz um mundo de diferença nas taxas de quadros em loop sobre esses dados, todos os quadros desenhados se a memória estiver estreita e fechada para minimizar falhas de cache, e é aí que o gerenciamento / controle de memória é tão útil. Exemplo visual simples em uma esfera com alguns milhões de vértices:
A descrição acima é realmente mais lenta que a minha versão mutável, uma vez que está testando uma representação persistente de uma estrutura de dados de uma malha, mas com isso de lado, eu costumava lutar para atingir essas taxas de quadros mesmo com metade desses dados (é certo que o hardware ficou mais rápido desde minhas lutas) ) porque não entendi como minimizar perdas de cache e uso de memória para dados de malha. As malhas são algumas das estruturas de dados mais complicadas com as quais lidei a esse respeito, porque armazenam tantos dados interdependentes que precisam permanecer sincronizados, como polígonos, arestas, vértices, tantos mapas de textura quanto o usuário deseja anexar, pesos ósseos, mapas de cores, conjuntos de seleção, alvos de metamorfose, pesos das arestas, materiais poligonais, etc. etc. etc.
Projetei e implementei vários sistemas de malha nas últimas duas décadas e a velocidade deles era muitas vezes proporcional ao uso de memória. Embora eu esteja trabalhando com muito mais memória do que quando comecei, meus novos sistemas de malha são 10 vezes mais rápidos que meu primeiro design (quase 20 anos atrás) e em grande parte porque usam cerca de 1/10 de a memória. A versão mais recente ainda usa compactação indexada para compor o máximo de dados possível e, apesar da sobrecarga de processamento da descompactação, a compactação melhorou o desempenho porque, novamente, temos tão pouca memória rápida preciosa. Agora posso ajustar um milhão de malhas poligonais com coordenadas de textura, vincagem de bordas, atribuições de material etc., juntamente com um índice espacial para ele em cerca de 30 megabytes.
Aqui está o protótipo mutável com mais de 8 milhões de quadrângulos e um esquema de subdivisão de multires em um i3 com uma GF 8400 (isso foi há alguns anos). É mais rápido que minha versão imutável, mas não é usado na produção, pois achei a versão imutável muito mais fácil de manter e o impacto no desempenho não é tão ruim. Observe que a estrutura de arame não indica facetas, mas patches (os fios são realmente curvas, caso contrário, toda a malha seria preta sólida), embora todos os pontos de uma faceta sejam modificados pelo pincel.
Enfim, eu só queria mostrar um pouco disso acima para mostrar alguns exemplos e áreas concretos em que o gerenciamento de memória é tão útil e também espero que as pessoas não pensem que eu estou apenas falando do meu rabo. Costumo ficar um pouco irritado quando as pessoas dizem que a memória é tão abundante e barata, porque isso é falar de memória lenta, como DRAM e discos rígidos. Ainda é tão pequeno e precioso quando falamos de memória rápida, e o desempenho de caminhos genuinamente críticos (por exemplo, caso comum, não para tudo) está relacionado à reprodução dessa pequena quantidade de memória rápida e à utilização da maneira mais eficaz possível. .
Para esse tipo de coisa, é realmente útil trabalhar com uma linguagem que permita projetar objetos de alto nível como C ++, por exemplo, enquanto ainda é possível armazenar esses objetos em uma ou mais matrizes contíguas, com a garantia de que a memória do todos esses objetos serão representados contiguamente e sem sobrecarga desnecessária de memória por objeto (por exemplo: nem todos os objetos precisam de reflexão ou despacho virtual). Quando você realmente passa por essas áreas críticas de desempenho, torna-se um aumento de produtividade ter esse controle de memória, digamos, brincando com conjuntos de objetos e usando tipos de dados primitivos para evitar sobrecarga de objeto, custos de GC e manter a memória acessada com frequência. juntos contíguos.
Portanto, o gerenciamento / controle da memória (ou a falta dela) é realmente uma razão dominante no meu caso para escolher qual idioma de maneira mais produtiva me permite resolver os problemas. Definitivamente, escrevo minha parte de código que não é crítica para o desempenho e, por isso, costumo usar Lua, que é muito fácil de incorporar a partir de C.