8
votes

Clonage profond d'objets Java (non haricots)

Le projet que je travaille actuellement a de nombreux objets sérialisés afin d'obtenir une copie profonde de l'objet existant. Cela fonctionne bien jusqu'à ce que nous ayons plusieurs appels au moment de l'exécution dans certaines cases, nous avons 100, 200 ou même 1000 appels entre composants et c'est là que nous sommes frappés par des maux de tête de performance.

La raison historique de la copie de ces objets clonées est que, deux composants différents travaillant sur les mêmes objets sous différentes fonctionnalités ne doivent pas se modifier mutuellement. Les modifications de l'interface utilisateur pivotante ne doivent pas modifier les valeurs d'objet dans le backend jusqu'à ce que la sauvegarde ou la touche synchronisée soit enfoncée.

Nous avons une base de code de grande taille, je pensais que si j'écris clone basé sur la réflexion, cela fonctionnera plus rapidement par rapport à la sérialisation, mais en raison de nos hiérarchies complexes d'objets ou d'une autre raison, cette approche est même plus lent.

J'ai également essayé d'utiliser des cloneUtils (Projet Sourceforge), qui est également plus lent (nous n'utilisons pas du tout hibernate). Spring Heortsutils n'est pas une option (je suppose de Documents qu'il utilise uniquement des haricots, c'est-à-dire introspection et au cas où je l'utilise si des champs sont exposés à l'aide d'un accesseur non standard, nous ne pourrons pas les copier).

Quelqu'un a-t-il une idée, améliore la performance tout en travaillant sur des copies différentes. Nous avons une option qui accélérera les choses au cas où nous fournirions nos propres méthodes de copie, au lieu de la sérialisation, mais cela a une réduction de la mise à jour de ces méthodes à chaque fois et si nous oublions que nous pourrions perdre des fonctionnalités.


2 commentaires

Lorsque vous avez besoin d'une copie profonde, avez-vous besoin tous des associations dépassées aussi bien? Ou seulement certains d'entre eux?


mettre en œuvre clone () manuellement (j'aime le clone, peu importe ce que j'entends parler) Si vous avez besoin d'une amélioration de la performance, aucune libération externe ne peut battre considérablement la sérialisation de Java (DE) car elle dépendra de la réflexion (dans le Meilleur cas, il peut opter pour la génération de code mais toujours ...)


4 Réponses :


0
votes

Il suffit de vous donner une idée de la manière dont vous pouvez améliorer les performances dans des cas comme ceci: Utilisez prototype modèle si vous n'utilisez pas déjà. Vous pourriez obtenir une certaine perfromance


6 commentaires

En fait, le prototype n'est pas différent de l'écriture de méthodes de copie dans mon cas, il y a 100 classes pour lesquelles je devrai écrire des méthodes de clone, car nous avons besoin d'une copie approfondie. Nous écrivons un mode de clone ou de copie et chaque fois que nous ajoutons ou supprimons un champ de l'une quelconque de ces classes, nous devrons modifier la méthode de la copie / clone.


Si vous utilisez clone () Ajout de primitives ou de classes non modifiables (URL, chaîne, chiffres, URI, etc.) ne nécessite pas de modification. Écrire des méthodes de clone prend probablement une minute.


Pas une minute, envisagez maintenant un CALS contenant HASHMAP, quels supports sont des objets d'un autre type (peut être un type de base afin que les enfants puissent être là aussi bien) et si ces objets contiennent également des collections. Vous devez écrire du clone pour chacun de ceux qui les profondément clonés. et assurez-vous que vous copiez des contenus de collecte dans chaque classe. L'interface clonable est cassée (Java efficace).


Vous avez besoin de 2 fonctions utilitaires pour créer des types de cartes / collections appropriés, puis de l'itération à travers eux et d'appeler Clone (). La principale et seule préoccupation est la visite du graphique correctement si vous avez des références cycliques. Toujours pas plus d'une minute. Honnêtement, je ne me souviens pas d'écrire Clone () qui m'a pris autant de temps.


ahh, oui et oublié que vous avez besoin d'une interface supplémentaire pour faire clone () public


Cela signifie que vous dites que nous fournissons une méthode de clone et sa mise en œuvre pour chaque classe (100 de ceux-ci) et vérifiez quelles classes sont stockées dans HASHMAP et que chacune de ces classes fournit un clone (). Chaque fois que nous ajoutons ou supprimons un champ à l'une des classes que nous devons changer la méthode clone (). Pour plus d'informations sur Cloning, voir Efficace Java Item 10. lien /chapter3.pdf



0
votes

Je doute qu'il y ait beaucoup que vous pouvez faire pour améliorer les performances de manière significative en suivant les approches que vous avez mentionnées. Malheureusement, il faut du temps pour copier un objet.

Penser légèrement latéralement, et clairement en fonction de la quantité de mémoire que vous avez ainsi que le rapport des lecteurs à écrire (surtout si vous avez de nombreux lecteurs pour chaque écriture), que diriez-vous de créer une cache de copies?


1 commentaires

Merci pour les réponses. Je ressens également la même chose, j'essaie de trouver si nous pouvons le refroidir correctement, cette zone a besoin de refactoring approprié.



1
votes

Vous pouvez éviter la réflexion par la génération de la classe dynamique, par exemple, en utilisant cglib . Pour chaque classe que vous utilisez, vous généreriez une «classe Cloner» contenant le code nécessaire à la copie. Cela ferait une réflexion inutile, à condition que tous les champs soient au moins forfaits-privés et vous mettez la classe de copieur dans le même paquet. Vous auriez besoin d'un CTOR par défaut et d'aucun champ final, aussi.

Ici, la sérialisation a un avantage, car elle crée des objets utilisant sun.misc.unsafe .

Mise en œuvre d'un Deepclone La méthode de chaque classe pourrait également être une option. Cela pourrait être même combiné à l'idée de cloner.


2 commentaires

L'accès sur le terrain est extrêmement rapide avec une réflexion / réflexion (ESP après SETACSsible (true) - supprime complètement les contrôles de sécurité). Vous pouvez même faire une utilisation non sécurisée.getxxx pour absolument en ligne. Sur une 2e pensée, le coût d'allocation de boxe pour les primitives doit encore être payé.


Vous pouvez utiliser les méthodes GetType et GetTySPE et Setxxx pour les primitives, cependant, cela coûtera toujours un certain temps. Vous pouvez utiliser non sécurisé.copymorior pour obtenir un clone peu profond, puis fixer tous les champs non primitifs. Vous auriez besoin de connaître la taille exacte de l'objet pour cela.



0
votes

Ce que vous décrivez est une approche de fusil de chasse pour gérer l'état mutable. Essayer de rendre le clone plus rapide ne vous donnera que des améliorations limitées (par exemple à un ordre de grandeur). En outre, comment clonerez-vous une prise, un flux ou une connexion de base de données?

Ce dont vous avez vraiment besoin est de refactoriser votre application avec une séparation appropriée de la commande / de la requête. De cette façon, vous saurez où vous changez d'objets et où vous n'êtes pas. Vous pouvez utiliser des tests d'unité pour vérifier cela si vous ne savez pas.

Il existe un certain nombre de techniques qui peuvent vous aider - vous pouvez modifier certains de vos objets à immuables (vous pouvez donc les partager naturellement, créant de nouvelles copies sur la mutation); Vous pouvez créer des objets mutables implémenter des interfaces en lecture seule et utiliser la vue RO dans l'interface graphique, etc.


2 commentaires

Oui, c'est une approche du fusil de chasse, j'admets, mais nous avons le temps de faire du temps que nous devons suivre. Ce projet est que les fonctionnalités bien et nouvelles sont livrées sous des délais très serrés.


Oui, c'est une approche du fusil de chasse, j'admets, mais nous avons le temps de faire du temps que nous devons suivre. Ce projet est assez vieux et de nouvelles fonctionnalités sont livrées sous des délais très serrés. Nous devons avoir des gains de performance en même temps, je ne voulais pas trop changer le code, je pensais appliquer ce clonant comme des conseils à notre code, qui appelle ObjectArtialisizer.CreatedCopy () (notre propre code) à faire deepculy .