7
votes

Est-ce qu'il vaut la peine de mettre en commun des bytes [] et de Char [] ou est-il préférable de simplement créer

Mon code fait beaucoup d'entrée / de sortie et cela implique souvent la création de matrices temporaires pour tenir des octets ou des caractères de certaines tailles - j'utilise souvent 4096. Je commence à me demander - sans tests réels - pour vérifier si ce serait Mieux vaut mettre en commun ces tableaux. Mon code changerait quelque chose comme celui-ci xxx

  • Il est plus rapide de prendre ou de créer simplement un octet avec 4096, ce qui signifie que certains travaux sont nécessaires pour Alloc Mem sur le tas, effacer les 4096 octets, etc.
  • Une piscine semble plus simple après tout, il suffit de vérifier une liste de la liste et de renvoyer la matrice.

    mise à jour J'ai écrit un petit programme qui a fait deux choses, créé des tableaux et a utilisé une piscine Apache Commons. Les deux bouclés beaucoup de fois (100 * 100 * 100) et créé / prenant une matrice remplie, puis libérés. J'ai ajouté quelques-uns au début pour réchauffer le JIT et ignorer les résultats de ceux-ci. Chaque exécution a couru la création et la piscine forme une douzaine de fois, alternant entre les deux.

    Il y avait peu de différence entre la piscine et créer des formulaires. Toutefois, si j'étais ajouté un tableau clair au rappel qui est tiré par Apache Commons Pool lorsqu'un instance est renvoyé dans un pool, la piscine est devenue beaucoup plus lente que la forme créée.


4 commentaires

Faites-vous ces opérations en parallèle ou pourriez-vous simplement réutiliser un tableau existant encore et encore?


Micro-optimisation détectée. La JVM est très efficace à la petite allocation d'objet et à la désaffectation - surtout si elles sont de courte durée. Traiter avec une piscine ajoute une autre couche de complexité et je voudrais pas descendre cette route (encore) à moins qu'il n'y ait pas de problème de performance analysé . Il y a même des cas de bord extrêmes où la mise en commun peut réduire considérablement les performances sur une nouvelle allocation basée sur la localité de données!


@Timo en parallèle - Imaginez une application Web typique.


@pst Oui, JVM est efficace permet d'imaginer que l'allocation d'espace pour le tableau est presque libre, mais il doit toujours effacer le tableau avant de vous remettre un tableau.


5 Réponses :


0
votes

La réponse est oui. Si vous devez faire beaucoup de ces tâches d'entrée / sortie, la mise en commun améliorera les performances et gardera l'empreinte mémoire plus petite.


4 commentaires

Ça sonne bien, mais, preuve / exemple où?


Mémoire: Prenez les matrices mentionnées ci-dessus de taille 4096. Chaque fois que vous en créez un nouveau, vous allouez 4096 octets de mémoire. Lorsque vous avez terminé, vous l'envoyez au collecteur des ordures, qui la détruit plus tard. Jusqu'à ce que la collecte des ordures soit exécutée, la mémoire restera réservée, de sorte que l'empreinte du programme est plus grande que nécessaire. Vous n'avez aucun contrôle sur cela. Lorsque vous utilisez la mise en commun, vous créez une quantité raisonnable de tableaux au début du programme, afin de traiter un peu plus que la charge moyenne. Vous avez une grande empreinte initiale, mais le programme n'est pas susceptible de se développer au-delà de la raison.


Performances: Chaque fois que vous créez une matrice, la mémoire doit être allouée et une entrée de la table de recherche doit être effectuée. Chaque fois que les ordures sont collectées, la mémoire inutilisée doit être libérée. Dans une piscine, tout ce que vous faites est de rechercher une adresse. Je suis d'accord, c'est minime. Sauf si vous avez un grand nombre de tâches, peut-être même avec une variation élevée entre les bas et les hauts. Ensuite, cela deviendra un facteur.


Mon petit essai de micro sorte de provision que l'utilisation d'une piscine ne blesse pas vraiment la performance. Le véritable avantage est la possibilité d'utiliser la piscine en tant que fournisseur tampon où ma taille de tampon n'est pas codée ou un paramètre à une classe mais plutôt extrait dans un autre composant. Dans ce cas, introduire une abstraction aide et me donne des options. La principale q vaut-t-elle la peine. La seule mauvaise chose est que les preneurs peuvent accrocher au tampon.



2
votes

Vous pouvez envisager d'utiliser les classes java.nio.buffer . Par exemple, vous pourriez avoir quelque chose comme ceci: xxx

chaque appel à fonctionner effacera le tampon prêt pour le prochain appel, mais vous ne serez pas alloué / trafiquant mémoire tout le temps. Flip et Effacer sont des opérations très rapides.

avoir un tampon par travailleur sera plus facile que de créer une piscine avec son travailleur Synchronisation associée Fun-and-jeux.

Edit: Notez que je suppose que vous générez un pool de travailleurs fixe afin que vous ne créez pas de nouveau tampon tout le temps.

Si vous ne pouvez pas avoir de piscine de travailleur fixe, vous pouvez envisager de créer un pool de buffer d'objets plutôt que des tableaux d'octets bruts. Cela dépend de la façon dont vous les utilisez.


5 commentaires

Ne fonctionnera pas parce que la plupart des API utilisent les anciennes classes IO INTERPRISTREAM / DEVEER / SURVEER / WRIDER / WRIDER.


Il y a vraiment deux parties à cette suggestion. (1) utiliser un bytebuffer; (2) Faites-en un membre de l'utilisation de la classe. (1) n'est viable que s'il utilise Nio. (2) n'est viable que si la classe n'est pas utilisée par plusieurs threads.


@EJP: (2) n'est viable que si chaque instance de la classe n'est pas utilisé par plusieurs threads. Chaque fil de travail peut avoir une instance assez heureusement.


@EJP Que dit Cameron - Tankx Cameron.


Corriger, merci, travail négligé de ma part. J'aurais aussi dû ajouter (3) chaque tampon n'est utilisé que par une méthode.



6
votes

Je ne participerais pas à la mise en commun tant qu'un problème de performance n'a été démontré.


2 commentaires

Votre préoccupation peut être répondue par le fait qu'une mise en œuvre d'un pool devait être apportée à la création d'un tableau à chaque fois pris. Cela signifie également que l'on peut régler la mémoire tampondiale de manière globale avec le codage de la couleur ou le passage d'une taille exacte.


@mp - Mais pourquoi perdre votre temps de le faire? Cette approche "piscine factice" n'est utile que pour mesurer si la mise en commun mérite d'être mise en œuvre après le fait ... et pour changer d'avis sans perdre réellement les modifications de code que vous avez apportées pour mettre en œuvre et utiliser l'API de mise en commun.



4
votes

Pools d'objet Ajouter une complexité à une application. En général, vous devez traiter avec:

  • Mise en œuvre des opérations d'acquisition / de libération dans une mode à fil de sécurité,
  • S'assurer que les objets sont toujours libérés et ne sont jamais retenus / utilisés après la libération,
  • Assurez-vous que les objets libérés sont "nettoyés" avant l'acquisition suivante et
  • croissant et rétrécissement de la taille de la piscine.

    Si vous faites une erreur dans la mise en œuvre du pool, vous pouvez introduire des bugs insidieux.

    ça vaut la peine? Eh bien, la réponse dépend des circonstances:

    • Si la mémoire est gravement contrainte, les pauses de GC sont un problème majeur, et / ou le coût d'attribution et d'initialisation d'un objet est important, alors probablement oui.

    • si le coût du "nettoyage" et l'objet est à peu près identique au coût amorti de l'attribution d'une nouvelle, alors il est douteux.

      Comprendre le dernier point, vous devez comprendre une copie de base ergonomie GC. Plus précisément si vous:

      • suppose un ensemble de travail constant de la taille d'objets accessibles,
      • Ignorer la finalisation des objets et les références douces / faibles / fantômes, et
      • Augmentez la taille totale du tas vers l'infini,

        Ensuite, le coût de la GC amorties d'allocation et de récupération de la mémoire pour l'objet dans Java approche le coût de la mémoire à zéro.

        Ainsi, si le coût du nettoyage d'un objet est approximativement équivalent à la surcharge de GC (zéro) + le coût du constructeur d'objet, la seule chose que vous gagnez par la mise en commun consiste à réduire le nombre de fois que le marquage / copie de GC se produit. Mais vous pouvez faire la même chose en donnant simplement à l'application un tas de plus grand.


7 commentaires

Premièrement, la piscine (sa interface) ne doit pas nécessairement être une piscine, une autre stratégie consiste à mettre en œuvre une usine. Il est impossible de veiller à ce que quelqu'un ne soit pas accroché à un tableau même s'ils le renvoient - car on ne peut pas envelopper la matrice avec un garde qui empêche l'utilisation par eux après son retour.


@MP - L'OP a posé des questions sur les piscines. Explicitement. En outre, une usine n'atteint pas l'objectif de recycler les matrices / tampons / peu importe, à moins que l'usine soit une enveloppe pour une sorte de piscine.


Premièrement, l'interface de la piscine permet à une usine d'être pressée dans les coulisses. D'autre part, la même chose n'est pas vraie en sens inverse, une interface d'usine avec simplement créer () n'a pas de méthode de libération () pour donner quelque chose de retour rendre impossible d'être une piscine.


Ce n'est pas parce que "la piscine" ne signifie pas que ce doit être une piscine, une usine qui accueille de nouveaux tableaux ne briserait aucun client, même s'il était perçu comme étant inefficace par rapport à une véritable mise en oeuvre de la mise en commun.


@mp - Je ne sais pas ce que vous êtes sur. L'ensemble de la question de l'OP concerne les objets de recyclage. Le modèle d'usine classique n'autorise pas cela, donc c'est (IMO) sans pertinence de la question. Lorsque vous ajoutez la ou les méthodes supplémentaires pour permettre le recyclage, vous utilisez le motif de piscine.


@Stepharc, l'interface de la piscine pourrait pour les arguments SE bienveillez-vous à une usine qui crée une nouvelle matrice chaque fois que la piscine.take () est appelée et ignorez simplement la matrice transmise à la piscine.Release (Array).


@mp - ... ne recyclant pas l'objet et ne rendant pas l'exercice de la mise en œuvre de la mise en commun inutile. (OK ... pas entièrement inutile. Vous pouvez utiliser cette approche après le fait pour mesurer si vous avez perdu votre temps en mettant en œuvre la mise en commun.)



1
votes

Pas vraiment une réponse, mais certains points importants à considérer si on veut utiliser la mise en commun des matrices par opposition à la création chaque fois qu'un tableau est requis.

  • Création d'un tableau est portéal au nombre d'éléments.
  • L'acquisition et la libération d'un tableau de retour à la piscine ont un coût fixe.
  • Si le tableau est supérieur à 4096 éléments, les frais généraux de la piscine sont inférieurs au coût de la création.
  • Création d'une matrice est moins chère que le nettoyage de la matrice s'il est important que le contenu soit effacé.
  • Partage d'une matrice ne doit pas être effectué si des données sensibles peuvent apparaître dans le tableau car il n'ya aucun moyen de garantir que le code renvoyant le tableau peut toujours conserver une référence.

0 commentaires