2010-10-31 4 views
2

J'ai utilisé InetAddress pour analyser les adresses IP, mais il est maintenant nécessaire de stocker le nom d'hôte si IP n'est pas disponible. J'ai donc présenté un hôte de classe.Où est la fuite de mémoire?

case class Host(name:String, ip:InetAddress) { 
    import Host.{addressToBytes, compareSeqs} 
    override def toString:String = if (ip!=null) {ip.getHostName} else {name} 
} 

object Host { 
    implicit def stringToPattern(s:String): Pattern = Pattern.compile(s) 
    val separators = Seq[Pattern]("\\.", ":") 
    def separatedStrToBytes(s:String, separator:Pattern): Array[Byte] = { 
     val fields = separator.split(s) 
     var rv = new Array[Byte](fields.length); 
     fields.map(_.toInt.toByte).copyToArray(rv, 0) 
     rv 
    } 
    implicit def strToBytes(s:String): Array[Byte] = { 
     for (sep <- separators) 
      if (sep.matcher(s).find()) 
       return separatedStrToBytes(s, sep) 
     null 
    } 
    implicit def strToHost(s:String):Host = { 
     var name = s 
     var ip:InetAddress = null 
     try { 
      val bytes = strToBytes(s) 
      if (bytes != null) { 
       ip = InetAddress.getByAddress(bytes) 
//    println("parsed ip: "+s) 
      } 
     } catch { 
      case e:UnknownHostException => 
     } 
     if (ip==null) { 
      ip = InetAddress.getByName(s) 
     } 
     new Host(name, ip) 
    } 
} 

Avec ce changement mon logiciel a commencé à échouer avec « java.lang.OutOfMemoryError: GC limite de frais généraux dépassé » dans separatedStrToBytes. Ai-je fait des erreurs de manipulation de la mémoire ici?

J'apprécie tous les commentaires sur le design. J'ai été incapable de raccourcir l'analyse en raison du besoin de Array [Byte] comme argument InetAddress.getByAddress. La plate-forme cible a Scala 2.7.7.

EDIT: J'ai remplacé l'analyse syntaxique avec des variables factices et découvert que mon programme échoue encore quelques mégaoctets de données analysées ultérieurement ailleurs. Chaque String.split (s: String) de remplacement avec Pattern.split (s: String) et le motif précompilé le font fonctionner un peu plus longtemps. Cela ne résout pas mon problème, mais cette question peut être fermée maintenant. J'ai toujours besoin de commentaires sur la conception.

Répondre

4

Votre code fonctionne très bien contre 2.8.0 (vous devriez envisager de migrer vers ce dernier, car il est déjà final et assez stable) - aucun OutOfMemory détecté.

Quelques optimisations que vous demandiez:

implicit def strToBytes(s:String)= (for {separator <- separators find(_.matcher(s).find)} yield separatedStrToBytes(s, separator)) getOrElse null 

implicit def separatedStrToBytes(s:String, separator:Pattern) = s split separator.pattern map(Integer.parseInt(_).toByte) 

scala> import Host._ 
import Host._ 
scala> strToBytes("127.0.0.1") 
res9: Array[Byte] = Array(127, 0, 0, 1) 
1

Il n'y a pas besoin d'analyser manuellement URIs comme celui-ci, il suffit d'utiliser la classe URI pré-existante de la bibliothèque standard Java: http://download.oracle.com/javase/6/docs/api/java/net/URI.html

ne le font pasutiliser la classe URL cependant, en aucun cas. Il a un algorithme de hachage fou qui résout d'abord le nom d'hôte à une adresse IP, qui est l'une des principales raisons pour lesquelles tant d'outils Java utilisant des URL (comme le gestionnaire de mise à jour Eclipse) sont très lents à démarrer lorsque vous ne le faites pas. avoir une connexion réseau

+1

Bonne idée. Comment puis-je utiliser URI pour analyser les points de terminaison UDP? Je peux extraire une chaîne IP du point de terminaison, que faire ensuite? Je ne peux pas trouver un moyen de faire usage de schéma personnalisé fonctionnant avec URI. – Basilevs

+0

Des exemples de ce que vous voulez exactement analyser seraient un bon point de départ ... –

+0

1288495632 17 10.3.0.1 138 10.3.255.255 138 461 eth0 unknown – Basilevs