Voici le problème:
Comme vous pouvez le voir, l'utilisation de la mémoire de ballons hors de contrôle! J'ai dû ajouter des arguments à la JVM pour augmenter la heapsize juste pour éviter des erreurs de mémoire insuffisante alors que je comprendre ce qu'il se passe. Pas bon!!!
Base Résumé de la Demande (pour le contexte)
Cette application est (finalement) va être utilisé pour la base de l'écran sur le CV et le modèle correspondant à des activités à des fins d'automatisation. Je veux atteindre le plus haut niveau de fréquence d'image possible pour regarder l'écran, et gérer l'ensemble de la transformation par l'intermédiaire d'une série de séparer la consommation de threads.
J'ai rapidement découvert que le stock Robot de classe est vraiment terrible de vitesse sage, donc j'ai ouvert la source, a pris toutes les évite la duplication des efforts et le gaspillage des frais généraux, et de reconstruit comme ma propre classe appelée FastRobot.
La Classe' Code:
public class FastRobot {
private Rectangle screenRect;
private GraphicsDevice screen;
private final Toolkit toolkit;
private final Robot elRoboto;
private final RobotPeer peer;
private final Point gdloc;
private final DirectColorModel screenCapCM;
private final int[] bandmasks;
public FastRobot() throws HeadlessException, AWTException {
this.screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
this.screen = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
toolkit = Toolkit.getDefaultToolkit();
elRoboto = new Robot();
peer = ((ComponentFactory)toolkit).createRobot(elRoboto, screen);
gdloc = screen.getDefaultConfiguration().getBounds().getLocation();
this.screenRect.translate(gdloc.x, gdloc.y);
screenCapCM = new DirectColorModel(24,
/* red mask */ 0x00FF0000,
/* green mask */ 0x0000FF00,
/* blue mask */ 0x000000FF);
bandmasks = new int[3];
bandmasks[0] = screenCapCM.getRedMask();
bandmasks[1] = screenCapCM.getGreenMask();
bandmasks[2] = screenCapCM.getBlueMask();
Toolkit.getDefaultToolkit().sync();
}
public void autoResetGraphicsEnv() {
this.screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
this.screen = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
}
public void manuallySetGraphicsEnv(Rectangle screenRect, GraphicsDevice screen) {
this.screenRect = screenRect;
this.screen = screen;
}
public BufferedImage createBufferedScreenCapture(int pixels[]) throws HeadlessException, AWTException {
// BufferedImage image;
DataBufferInt buffer;
WritableRaster raster;
pixels = peer.getRGBPixels(screenRect);
buffer = new DataBufferInt(pixels, pixels.length);
raster = Raster.createPackedRaster(buffer, screenRect.width, screenRect.height, screenRect.width, bandmasks, null);
return new BufferedImage(screenCapCM, raster, false, null);
}
public int[] createArrayScreenCapture() throws HeadlessException, AWTException {
return peer.getRGBPixels(screenRect);
}
public WritableRaster createRasterScreenCapture(int pixels[]) throws HeadlessException, AWTException {
// BufferedImage image;
DataBufferInt buffer;
WritableRaster raster;
pixels = peer.getRGBPixels(screenRect);
buffer = new DataBufferInt(pixels, pixels.length);
raster = Raster.createPackedRaster(buffer, screenRect.width, screenRect.height, screenRect.width, bandmasks, null);
// SunWritableRaster.makeTrackable(buffer);
return raster;
}
}
En substance, tout ce que j'ai modifié à partir de l'original est le déplacement de plusieurs des allocations à partir de la fonction des organes, et de les définir comme des attributs de la classe de sorte qu'ils ne sont pas appelée à chaque fois. Faire cela eu une importante incidence sur les taux de trame. Même sur mon gravement sous alimenté ordinateur portable, il est passé de ~4 fps avec le Robot de la classe, à ~30 fps avec mon FastRobot classe.
Premier Test:
Quand j'ai commencé à outofmemory des erreurs dans mon programme principal, j'ai monté cette épreuve très simple de garder un œil sur la FastRobot. Note: ceci est le code qui produit le tas profil ci-dessus.
public class TestFBot {
public static void main(String[] args) {
try {
FastRobot fbot = new FastRobot();
double startTime = System.currentTimeMillis();
for (int i=0; i < 1000; i++)
fbot.createArrayScreenCapture();
System.out.println("Time taken: " + (System.currentTimeMillis() - startTime)/1000.);
} catch (AWTException e) {
e.printStackTrace();
}
}
}
Examinés:
Il ne fait pas cela tous les temps, ce qui est vraiment étrange (et frustrant!). En fait, il le fait rarement à tous avec le code ci-dessus. Toutefois, la question de la mémoire devient facilement reproductible si j'ai plusieurs boucles for dos à dos.
Test 2
public class TestFBot {
public static void main(String[] args) {
try {
FastRobot fbot = new FastRobot();
double startTime = System.currentTimeMillis();
for (int i=0; i < 1000; i++)
fbot.createArrayScreenCapture();
System.out.println("Time taken: " + (System.currentTimeMillis() - startTime)/1000.);
startTime = System.currentTimeMillis();
for (int i=0; i < 500; i++)
fbot.createArrayScreenCapture();
System.out.println("Time taken: " + (System.currentTimeMillis() - startTime)/1000.);
startTime = System.currentTimeMillis();
for (int i=0; i < 200; i++)
fbot.createArrayScreenCapture();
System.out.println("Time taken: " + (System.currentTimeMillis() - startTime)/1000.);
startTime = System.currentTimeMillis();
for (int i=0; i < 1500; i++)
fbot.createArrayScreenCapture();
System.out.println("Time taken: " + (System.currentTimeMillis() - startTime)/1000.);
} catch (AWTException e) {
e.printStackTrace();
}
}
}
Examiné
Le contrôle de segment de mémoire est maintenant reproductible je dirais environ 80% du temps. J'ai regardé tout bien que le générateur de profils, et la chose de la plupart remarque (je pense) est que le garbage collector apparemment arrêts de droit comme la quatrième et dernière boucle commence.
Le format de sortie le code ci-dessus a donné les horaires suivants:
Time taken: 24.282 //Loop1
Time taken: 11.294 //Loop2
Time taken: 7.1 //Loop3
Time taken: 70.739 //Loop4
Maintenant, si vous additionnez les trois premières boucles, il ajoute à 42.676, qui étrangement correspond au moment exact où le garbage collector s'arrête, et la mémoire de clous.
Maintenant, c'est mon premier rodéo avec profilage, pour ne pas mentionner la première fois que j'ai jamais même pensé à propos de la collecte des ordures, c'était toujours quelque chose qui fonctionne comme par magie dans l'arrière-plan -- donc, je ne suis pas sûr de ce que, si quelque chose, je l'ai découvert.
Autres Informations Sur Votre Profil
Augusto a suggéré de regarder le profil de la mémoire. Il y a 1500+ int[]
qui sont répertoriés comme "inaccessible, mais pas encore recueillis." Ce sont certainement l' int[]
tableaux que l' peer.getRGBPixels()
crée, mais pour une raison quelconque, ils ne sont pas détruits. Ce complément d'info, malheureusement, ne fait qu'ajouter à ma confusion, que je ne suis pas sûr pourquoi, la GC ne serait pas la collecte des
Profil à l'aide de petits tas argument -Xmx256m:
Au irreputable et Chaude Lèche suggestion j'ai mis le max de la taille du segment de quelque chose de beaucoup plus petite. Bien que cela ne l'empêcher de faire le 1 go de sauter dans l'utilisation de la mémoire, il n'explique toujours pas pourquoi le programme est en montgolfière à son maximum, taille du tas à l'entrée de la 4ème itération.
Comme vous pouvez le voir, la cause exacte existe toujours, c'est juste plus petit. ;) Le problème avec cette solution est que le programme, pour une raison quelconque, est toujours de manger à travers la totalité de la mémoire, il peut -- il y a aussi un changement marqué dans les fps de la performance à partir de la première itérations, qui consomme très peu de mémoire, et la version finale, qui consomme plus de mémoire que peut.
La question reste de savoir pourquoi est-il de la montgolfière à tous?
Résultats après avoir atteint une Force de "Garbage Collection" bouton:
Au jtahlborn de la suggestion, j'ai frappé à la Force de la Collecte des Ordures bouton. Il a fonctionné à merveille. Il va de 1go de l'utilisation de la mémoire, jusqu'à la basline de 60 mo environ.
Donc, cela semble être le remède. Maintenant, la question est, comment puis-je pro grammaticalement de la force de la GC pour ce faire?
Résultats après l'ajout de locaux par les Pairs de la fonction de la portée:
À la David Eaux suggestion, j'ai modifié le createArrayCapture()
fonction de sorte qu'il est titulaire d'un local Peer
objet.
Malheureusement, aucun changement dans l'utilisation de la mémoire de modèle.
Obtient quand même énorme sur la 3ème ou 4ème itération.
La Mémoire De La Piscine De L'Analyse:
Les captures d'écran des différents pools de mémoire
Toutes les piscines:
Eden Piscine:
Old Gen:
Juste au sujet de tous les de l'utilisation de la mémoire semble tomber dans cette piscine.
Remarque: PS Survivant de l'Espace avait (apparemment) 0 utilisation
Je suis parti avec plusieurs questions:
(a) la Poubelle Profiler graphique de dire ce que je pense que cela signifie? Ou je confonds corrélation avec le lien de causalité? Comme je l'ai dit, je suis dans une région inconnue de ces questions.
(b) Si c' est le garbage collector... que dois-je faire à ce sujet..? Pourquoi est-il cesser, et de courir à un taux réduit pour le reste du programme?
(c) Comment puis-je résoudre ce problème?
Quelqu'un aurait-il une idée de ce qui se passe ici?