2

Lors de certains tests finaux d'une bibliothèque de classes que j'écris pour Windows Mobile (à l'aide de Compact Net Framework 2.0), j'ai rencontré une exception de MOO. Fondamentalement, ma bibliothèque charge d'abord un dictionnaire-fichier (un fichier texte ordinaire avec une liste de mots) et ensuite un autre fichier basé sur le dictionnaire (je l'appelle KeyMap) dont la taille est plus ou moins la même que celle précédemment chargée dictionnaire..net Exception OutOfMemory

Tout a bien fonctionné (en utilisant l'émulateur et mon vrai périphérique) avec les fichiers ci-dessus jusqu'à ce que j'essaie de charger un dictionnaire espagnol qui a une taille d'environ 2,7 Mo. Les autres dictionnaires de langue que j'ai utilisés jusqu'ici sans aucune exception de MOO s'élèvent à environ 1,8 Mo chacun. Avec le dictionnaire espagnol, je peux charger le premier fichier sans aucun problème mais quand j'essaye de lire le deuxième fichier, j'obtiens l'erreur OOM.

Ci-dessous j'ai écrit le code que j'utilise. Fondamentalement, je lis les fichiers et affecte son contenu à une variable de chaîne (DictData et TextKeyMap). Ensuite, je fais un Split sur la variable de chaîne pour transmettre le contenu à un tableau de chaînes (Dict et KeyMap).

'Loading Dictionary works 
Dim ReadDictionary As StreamReader = New StreamReader(DictPath, Encoding.UTF8) 
    DictData = ReadDictionary.ReadToEnd() 
      ReadDictionary.Close() 
      Dict = DictData.ToString.ToUpper.Split(mySplitSep.ToCharArray) 'mySplitSep=chr(10) 
      DictData = "" 'perhaps "nothing" is better 

'Loading KeyMap gives me error 
Dim ReadHashKeyMap As StreamReader = New StreamReader(HashKeyMapPath, Encoding.UTF8) 
    TextKeyMap = ReadHashKeyMap.ReadToEnd() '<-- OOM-error 
      ReadHashKeyMap.Close() 
      KeyMap = TextKeyMap.ToString.Split(mySplitSep.ToCharArray) 'mySplitSep=chr(10) 
      TextKeyMap = "" 'perhaps "nothing" is better 

Je suis un passe-temps-programmeur sans connaissance expert donc mon code ci-dessus peut probablement être améliorée. Au lieu d'utiliser ReadToEnd, j'ai essayé de lire chaque ligne dans une boucle For mais j'ai eu la même erreur (c'était aussi plus lent).

Je suppose que l'erreur est due à la limitation de 32 Mo de mémoire contiguë dans Windows Mobile.

N'importe qui parmi vous peut m'aider, peut-être en suggérant des solutions alternatives? Peut-être le problème est dû à mon code de merde montré ci-dessus? Qu'en est-il, en chargeant le deuxième fichier en un autre fil? Cela pourrait-il fonctionner?

Toute l'aide que je peux obtenir sera grandement appréciée.

Modifier: J'ai posé une question similaire il y a quelque temps (here), mais que l'on était plus liée à traiter la réception d'octets et a été résolu en utilisant des morceaux. Dans ce cas, j'ai affaire à des cordes.

Édition2: Cette bibliothèque est une bibliothèque de vérification d'orthographe. Cela fonctionne assez bien et implémente des techniques assez avancées telles que les algorithmes Soundex et DoubleMetaPhone. Le seul problème majeur à ce jour est le problème mentionné ci-dessus avec un énorme fichier texte pour l'espagnol. D'autres dictionnaires sont OK. Pour plus d'informations, veuillez consulter this link

+0

Pouvez-vous nous donner un exemple de ce qu'il y a dans les fichiers? –

+0

peut-être lié et utile? -> http://stackoverflow.com/questions/678025/net-out-of-memory-exceptions-in-windows-mobile-how-to-overcome-this-problem – hometoast

+0

Eric: c'est simplement une liste de mots: " voiture "" voitures "" panier "etc (chaque mot oa une ligne séparée) – moster67

Répondre

3

Comme vous n'avez pas dit ce que vous utilisez ce fichier car je suppose que vous cherchez juste un mot pour une raison quelconque.

Tout d'abord, ce n'est probablement pas une bonne idée d'essayer de charger le fichier complet en mémoire. Au lieu de cela, il peut être plus productif de rechercher dans le fichier les données (mot) dont vous avez besoin et, peut-être, de garder une sorte d'information d'indexation en mémoire pour accélérer les choses un peu. Comme les données que vous essayez de rechercher sont juste une liste de mots, il pourrait être une bonne idée de numériser le fichier et d'enregistrer dans un dictionnaire où la première lettre d'un mot change. Par exemple, A commence à la ligne 0; B commence à la ligne 200; C commence à la ligne 300, etc. Utilisez ces deux informations pour remplir votre dictionnaire; la lettre est la clé et le numéro de ligne est la valeur. En effet, le dictionnaire devient un index de haut niveau dans le fichier de liste de mots. Ce dictionnaire est également très petit. Puis, lorsque vous commencez à chercher un mot, utilisez la première lettre du mot pour rechercher le dictionnaire. Cela vous obtiendra le numéro de ligne où les mots qui commencent par cette lettre sont situés dans le fichier. Armé avec le numéro de ligne (re) ouvrir le fichier et aller directement à cette ligne dans le fichier Word en déplaçant le pointeur de flux sur la ligne cible. Ensuite, recherchez le mot cible à partir de là. Soit effectuer une recherche séquentielle, une ligne à la fois (pas recommandé, il sera assez lent mais sera plus facile à coder). Ou, recherchez le mot en utilisant un binary chop (beaucoup plus rapide, mais plus difficile à coder). Bien que pour ce dernier vous devrez également savoir où les mots qui commencent par la lettre cible s'arrêtent dans le fichier que vous allez rechercher une section du fichier. Je vous recommande également de faire le mot recherche dans le fichier plutôt que de charger tous ces mots en mémoire, sinon vous pourriez être de retour à l'endroit où vous commencez avec des erreurs de MOO.

Si vous n'êtes pas sûr de quoi que ce soit, faites un commentaire ici et je ferai de mon mieux pour y répondre.

Bonne chance

+0

Bonne entrée! BinarySearch est déjà utilisé quand et où c'est possible. Alors que le 1er fichier (la liste de mots) doit être chargé comme indiqué dans mon code (nécessaire pour d'autres algorithmes dans ma bibliothèque), votre idée est toujours bonne, surtout en ce qui concerne le 2ème fichier. et charger/accéder à la même chose seulement si nécessaire. Bien sûr, cela impliquerait beaucoup d'accès aux fichiers et probablement une perte de performance assez importante mais quand même ... Je vais essayer! Merci! – moster67

+0

s'il vous plaît voir mon edit2 pour quelques informations supplémentaires concernant la bibliothèque – moster67

+0

Merci pour le feed back. Y a-t-il une chance que vous puissiez voter pour ma réponse? ;-) Concernant le deuxième fichier. Vous pouvez essayer de rechercher le fichier sur un fil d'arrière-plan, qui devrait au moins garder votre interface utilisateur sensible. –

2

Il semble que vous n'ayez pas assez de mémoire pour conserver tout le texte de tous les fichiers en mémoire en même temps. Vous devrez peut-être trouver une stratégie qui met en cache un sous-ensemble limité de fichiers et qui soit suffisamment intelligente pour revenir au fichier lorsque quelque chose est demandé qui n'est pas dans le cache. Si tout le but de l'exercice est que vous n'ayez pas à revenir aux fichiers (par exemple, créer une sorte d'index), vous pouvez également essayer d'être "intelligent" et trouver une alternative représentation pour le texte en mémoire qui tire parti de la nature très compressible de la plupart des langues occidentales.

+0

GregD: le fichier KeyMap est en fait un fichier index du dictionnaire. Je pourrais le diviser en parties plus petites et charger la partie nécessaire en cas de besoin, mais cela ralentirait le processus de correction d'orthographe qui récupère les suggestions, surtout dans ce cas car il s'exécute sur Windows Mobile avec une mémoire et des ressources matérielles limitées. – moster67

2

Je dirais que la ligne problématique est celle-ci:

Dict = DictData.ToString.ToUpper.Split(mySplitSep.ToCharArray) 

Le GC n'est pas en mesure de suivre la création d'objets temporaires derrière cette ligne simple. "ToUpper" crée une copie de la chaîne d'origine, et "Split" crée un nouveau tableau à partir de cette copie (et utilise probablement plus de mémoire pour l'algo lui-même). D'ailleurs, l'appel à "ToString" est inutile, DictData est déjà une chaîne, non?

Personnellement, je lirais du flux par morceaux, et ferais les morceaux de séparation par morceaux, dans une liste <>. Mais si vous voulez garder votre code court, essayer, on ne sait jamais:

DictData = ReadDictionary.ReadToEnd() 
ReadDictionary.Close() 
DictData = DictData.ToUpper() 
GC.Collect() 
Dict = DictData.Split(mySplitSep.ToCharArray) 
DictData = Nothing 
GC.Collect() 

Je trouve jamais une bonne solution pour appeler GC.Collect. L'appeler signifie généralement "quelque chose de mieux aurait dû être fait". Mais la gestion de la mémoire sous .NET CF est parfois douloureuse.

+0

slimCODE: Je vous ai dit que mon code était merdique! Vous avez raison - DictData est une chaîne mais pour obtenir la conversion en UpperCase, j'ai dû ajouter ".To.String" afin d'obtenir ".To.Upper (en utilisant Intellisense) ou peut-être que je me trompe. t vérifier maintenant – moster67

+0

slimCode: Pourriez-vous élaborer votre idée de "séparer les pièces par morceaux dans une liste <>" Je ne comprends pas ce que vous voulez dire.Pour vos suggestions de code, je vais essayer.Merci! " – moster67

+0

slimCODE: J'ai essayé votre code, en appliquant la même chose au 1er et 2ème fichier mais malheureusement, je reçois toujours des exceptions OOM. – moster67

Questions connexes