2013-09-07 14 views
5

Sto provando a compilare un file C++ grande 5,7 MB. Sto costruendo un eseguibile Linux a 64 bit su un sistema Linux a 64 bit. g ++ 4.7.2 purtroppo non è cooperativo:Compilando una mappa più grande (~ 6 MB) inizializzando il file C++ con gcc

g++: internal compiler error: Killed (program cc1plus) 

Osservare con top indica che il processo raggiunge circa 2,2 giga di memoria prima che ciò accada. Ho provato a impostare --param gcc-min-expand=0 e ho anche giocato con --param gcc-min-heapsize ma questo non risolve il problema. Disabilitare l'ottimizzazione con -O0 non è stato d'aiuto.

Ho anche provato a compilare con clang, ma i risultati erano simili. Segmentato dopo aver superato anche 2 gigabyte di memoria. Non ho provato nessuna opzione extra con clang perché non sono così familiare con esso.

Il file sorgente in questione è costituito dall'inizializzazione in stile C++ 11 di alcune mappe.

typedef std::map<std::string, int> StringToIntMap; 
StringToIntMap someData = {{"SOMESTRING", 1}, ..}; 

quello che voglio è preferibilmente di compilare il file con gcc, anche se clang può funzionare, invece, posso anche vivere con essa. Sarebbe anche utile scoprire, da qualcuno che conosce gli interni, cosa sta succedendo dietro le quinte. Se ho una mappa di 300.000 elementi in cui le stringhe sono lunghe circa 5 byte e corrisponde a uno int corrisponde a pochi megabyte di dati e non riesco a immaginare facilmente come l'inizializzatore salta fino al punto di richiedere gigabyte compilare.

E per anticipare i commenti che non dovrei avere un file sorgente così grande. So che posso leggere i dati da un file di dati in fase di esecuzione, e questo è ciò che il programma fa ora, ma il mio caso d'uso è tale che il tempo di esecuzione del programma è il fattore più importante.

+0

lol. Sono sicuro che l'appendice B dello standard dà al compilatore il permesso di iniziare a fallire un po 'prima di quello:/ – sehe

+3

Spostare questo nel codice sorgente non guadagnerà molto nella realtà. Al momento, è necessario il tempo M per caricare il tempo eseguibile + N per inizializzare le mappe. Con i dati pre-caricati ti ritroverai con un eseguibile che richiede (circa) il tempo di caricamento M + N. Data paginazione richiesta, ciò avverrà come tempo M per iniziare l'esecuzione e N volta per pagina nei dati in fase di esecuzione. Ultima differenza: molto più lavoro, ma quasi nessuna differenza nella velocità di esecuzione. –

+0

@JerryCoffin Ora se questo fosse un 'boost :: flatmap', potrebbe essere molto meglio, ma anche in questo caso, l'inizializzazione' constexpr' potrebbe essere migliore. – sehe

risposta

4

Il compilatore può impostare limiti di implementazione definiti sulla quantità di livelli/quantità supportati in molti costrutti linguistici.

Appendice B elenca le quantità minime richiesto per un conforme compilatore.

Da Appendice B, grassetto i più rilevanti:

I limiti possono limitare le quantità che includono quelli descritti di seguito o altri . Il numero di parentesi dopo ogni quantità è raccomandato come il minimo per quella quantità. Tuttavia, queste quantità sono solo linee guida e non determinano la conformità allo .

  • Livelli di annidamento di istruzioni composte, strutture di controllo di iterazione e strutture di controllo di selezione [256].
  • Livelli di annidamento di inclusione condizionale [256].
  • Dichiaratori di puntatori, array e funzioni (in qualsiasi combinazione) che modificano un tipo plete di classe, aritmetico o incom- in una dichiarazione [256].
  • Livelli di annidamento di espressioni parentesi all'interno di un'espressione completa [256].
  • Numero di caratteri in un identificativo interno o nome macro [1 024].
  • Numero di caratteri in un identificatore esterno [1 024].
  • Identificatori esterni in un'unità di traduzione [65 536].
  • Identificatori con ambito di blocco dichiarato in un blocco [1 024].
  • Identificatori di macro definiti simultaneamente in un'unità di traduzione [65 536].
  • Parametri in una definizione di funzione [256].
  • Argomenti in una chiamata di funzione [256].
  • Parametri in una definizione macro [256].
  • Argomenti in una macro invocazione [256].
  • Caratteri in una riga di origine logica [65 536].
  • Caratteri in una stringa letterale (dopo la concatenazione) [65 536].
  • Dimensione di un oggetto [262 144].
  • Livelli di annidamento per file #include [256].
  • Case label per un'istruzione switch (esclusi quelli per qualsiasi istruzione switch nidificata) [16 384].
  • Membri dati in una singola classe [16 384].
  • Costanti di enumerazione in una singola enumerazione [4 096].
  • Livelli di definizioni di classi annidate in una singola specifica membro [256]
  • Funzioni registrate da atexit() [32].
  • Funzioni registrate da at_quick_exit() [32].
  • Classi di base dirette e indirette [16 384].
  • Classi di base diretta per una singola classe [1 024].
  • Membri dichiarati in una singola classe [4 096].
  • Funzioni virtuali di override finale in una classe, accessibili o meno [16 384].
  • Basi virtuali dirette e indirette di una classe [1 024].
  • Membri statici di una classe [1 024].
  • Dichiarazioni di amicizia in una classe [4 096].
  • dichiarazioni di controllo di accesso in una classe [4 096].
  • Inizializzatori membro in una definizione costruttore [6 144].
  • Qualifiche di ambito di un identificatore [256].
  • Specifiche esterne nidificate [1 024].
  • Chiamate ricorsive della funzione constex [512].
  • Argomenti del modello in una dichiarazione modello [1 024].
  • Creazioni di template annidate in modo ricorsivo, inclusa la sostituzione durante la deduzione dell'argomento modello (14.8.2) [1 024].
  • Blocco per gestori per try [256].
  • Throw specifiche su una dichiarazione di singola funzione [256].
  • Numero di segnaposto (20.8.9.1.4) [10]

Ora, liste di inizializzazione sono in realtà solo 'costruito' da un certo numero di argomenti e apparentemente GCC non abbastanza supporta la quantità/volumi che hai fornito.

Ci potrebbero essere opzioni nella pagina man per alleviare questo:

  • -mlarge-data (che è il default)
  • -mlarge-text (anche il default)
+0

Questo spiega sicuramente perché il compilatore potrebbe fallire secondo lo standard, ma in realtà non spiega l'uso della memoria di oltre 2 concerti. L'inizializzatore viene generato da molti argomenti, e in questo caso suppongo che siano della forma 'pair (chiave, valore)'. In che modo provare a costruire un elenco troppo lungo di argomenti del genere riesce a utilizzare 2 gigabyte di memoria? – DUman

+0

@ user1264727 Non lo so. C'è un modo per scoprirlo: esegui il debug del compilatore (è open source). O, sai, puoi cambiare il tuo codice per usare un approccio diverso. – sehe

+1

Questa è una domanda nata più per curiosità riguardo al funzionamento interno :) Ora sembra chiaro che l'utilizzo di questo approccio non ne valga la pena, anche se potrebbe essere costretto a compilare. – DUman

Problemi correlati