Detalhes técnicos
0 [main] us 0 init_cheap: VirtualAlloc pointer is null, Win32 error 487
AllocationBase 0x0, BaseAddress 0x68570000, RegionSize 0x2A0000, State 0x10000
PortableGit\bin\bash.exe: *** Couldn't reserve space for cygwin's heap, Win32 error 0
Esse sintoma, por si só, não tem nada a ver com bases de imagens de executáveis, seções de memória compartilhada do Cygwin corrompidas, versões conflitantes de DLLs etc.
É o código Cygwin que falha ao alocar um pedaço grande de ~ 5 MB de memória para seu heap neste endereço fixo 0x68570000, enquanto apenas um buraco ~ 2,5 MB grande estava aparentemente disponível lá. O código relevante pode ser visto na fonte msysgit .
Por que essa parte do espaço de endereço não é livre?
Pode haver muitas razões. No meu caso, foram alguns outros módulos carregados em um endereço conflitante:
O último endereço seria em torno de 0x68570000 + 5 MB = 0x68C50000, mas existem essas DLLs relacionadas ao WOW64 carregadas de 0x68810000 para cima, que bloqueiam a alocação.
Sempre que houver alguma DLL compartilhada, o Windows em geral tenta carregá-la no mesmo endereço virtual em todos os processos para salvar algum processamento de realocação. É apenas uma questão de má sorte que esses componentes do sistema tenham sido carregados de alguma forma em um endereço conflitante dessa vez .
Por que existe o Cygwin no seu Git?
Porque o Git é uma suíte rica que consiste em alguns comandos de baixo nível e muitos utilitários úteis, e principalmente desenvolvidos em sistemas similares ao Unix. Para poder construí-lo e executá-lo sem reescrever em massa, ele precisa de pelo menos um ambiente parecido com o Unix.
Para conseguir isso, as pessoas inventaram o MinGW e o MSYS - um conjunto mínimo de ferramentas de criação para desenvolver programas no Windows de maneira semelhante ao Unix. O MSYS também contém uma biblioteca compartilhada msys-1.0.dll
, que ajuda com alguns dos problemas de compatibilidade entre as duas plataformas durante o tempo de execução. E muitas partes foram tiradas do Cygwin, porque alguém já tinha que resolver os mesmos problemas lá.
Portanto, não é Cygwin, é a DLL de tempo de execução do MinGW que está se comportando de forma estranha aqui.
No Cygwin, esse código realmente mudou muito desde o que está no MSYS 1.0 - a última mensagem de confirmação desse arquivo diz "Importar Cygwin 1.3.4", que é de 2001!
O Cygwin atual e a nova versão do MSYS - MSYS2 - já possuem uma lógica diferente, o que é esperançosamente mais robusto. São apenas as versões antigas do Git for Windows que ainda foram criadas usando o antigo sistema MSYS quebrado.
Soluções limpas:
- Instale o Git para Windows 2 - ele foi desenvolvido com o novo MSYS2 , com manutenção adequada e também possui muitos recursos novos, muitas correções de bugs, melhorias de segurança e assim por diante. Se possível, também é recomendável usar a versão de 64 bits . Mas a solução alternativa de rebase é executada automaticamente nos bastidores para sistemas de 32 bits, portanto as chances de o problema acontecer também devem ser menores.
- Simplesmente reiniciar o computador para limpar o espaço de endereço (carregar esses módulos em um endereço aleatório diferente) pode funcionar, mas, na verdade, basta atualizar para o Git for Windows 2 para obter as correções de segurança, se nada mais.
Soluções Hacky:
PATH
Às vezes, alterar pode funcionar porque pode haver versões diferentes de versões msys-1.0.dll
diferentes do Git ou de outros aplicativos baseados em MSYS, que talvez usem endereços diferentes, tamanhos diferentes desse heap etc.
- Rebasing
msys-1.0.dll
pode ser um desperdício de tempo, porque 1) como uma DLL, já possui informações de realocação e 2) "em qualquer versão do sistema operacional Windows, não há garantia de que uma (...) DLL sempre seja carregada no mesmo espaço de endereço" de qualquer maneira ( fonte ). A única maneira de ajudar é se o msys-1.0.dll
próprio carregamento no endereço conflitante que está tentando usar. Aparentemente, esse é o caso algumas vezes, pois é isso que os caras do Git for Windows estão fazendo automaticamente em sistemas de 32 bits .
- Considerando as descobertas acima, eu originalmente corrigi o
msys-1.0.dll
binário para usar um valor diferente _cygheap_start
e isso resolveu o problema imediatamente.