Je bezpečný spôsob, ako používať Čistič na registráciu poslucháč?

0

Otázka

Mám Swing akcie trieda, ktorá funguje takto:

package org.trypticon.hex.gui.datatransfer;

import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.FlavorListener;
import java.awt.event.ActionEvent;
import javax.annotation.Nonnull;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.TransferHandler;

import org.trypticon.hex.gui.Resources;
import org.trypticon.hex.gui.util.FinalizeGuardian;
import org.trypticon.hex.gui.util.FocusedComponentAction;

public class PasteAction extends FocusedComponentAction {
    private final FlavorListener listener = (event) -> {
        // this method in the superclass calls back `shouldBeEnabled`
        updateEnabled();
    };

    @SuppressWarnings({"UnusedDeclaration"})
    private final Object finalizeGuardian = new FinalizeGuardian(() -> {
        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        clipboard.removeFlavorListener(listener);
    });

    public PasteAction() {
        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        clipboard.addFlavorListener(listener);
    }

    @Override
    protected boolean shouldBeEnabled(@Nonnull JComponent focusOwner) {
        TransferHandler transferHandler = focusOwner.getTransferHandler();
        if (transferHandler == null) {
            return false;
        }

        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        DataFlavor[] flavorsInClipboard = clipboard.getAvailableDataFlavors();
        return transferHandler.canImport(focusOwner, flavorsInClipboard);
    }

    @Override
    protected void doAction(@Nonnull JComponent focusOwner) throws Exception {
        Action action = TransferHandler.getPasteAction();
        action.actionPerformed(new ActionEvent(
            focusOwner, ActionEvent.ACTION_PERFORMED, (String) action.getValue(Action.NAME)));
    }
}

Na FinalizeGuardian uvedené je tu v súčasnosti vykonáva podľa finalize():

package org.trypticon.hex.gui.util;

public final class FinalizeGuardian {
    private final Runnable cleanupLogic;

    public FinalizeGuardian(Runnable cleanupLogic) {
        this.cleanupLogic = cleanupLogic;
    }

    @Override
    protected final void finalize() throws Throwable {
        try {
            cleanupLogic.run();
        } finally {
            super.finalize();
        }
    }
}

Takže, z pochopiteľných dôvodov, chcela by som sa prepnúť na používanie Cleaner za to.

Prvý pokus bol niečo ako toto:

package org.trypticon.hex.gui.util;

import java.lang.ref.Cleaner;

public final class FinalizeGuardian {
    private static final Cleaner cleaner = Cleaner.create();

    public FinalizeGuardian(Runnable cleanupLogic) {
        cleaner.register(this, cleanupLogic);
    }
}

Problém je, že teraz objektu nikdy sa stáva phantom dosiahnuteľné, pretože:

  • Cleaner sám má silný odkaz na cleanupLogic
  • cleanupLogic drží odkaz na listener s cieľom odstrániť poslucháč
  • listener drží odkaz na akciu trieda aby sa hovor updateEnabled na to
  • akcie triedy drží odkaz na FinalizeGuardian tak, že to ani nemôže byť zbierané predčasne

Pretože FinalizeGuardian sám nikdy sa stáva phantom dosiahnuteľný čistiaci prostriedok nikdy nebude tzv.

Takže to, čo by som chcel vedieť, je, existuje spôsob, ako reštrukturalizovať tento dodržiavať pravidlá potrebné na to, aby Cleaner pracovať správne, že nebude zahŕňať lámanie zapuzdrenie pohybom poslucháč mimo môjho akcie trieda?

garbage-collection java swing
2021-11-24 01:39:09
1

Najlepšiu odpoveď

3

Tak dlho, ako FlavorListener je registrovaná na udalosť zdroj, to sa nikdy nestane nedosiahnuteľný (ako dlho, ako zdroj udalosti je stále dosiahnuteľný). To znamená, že PasteAction stupňa, ktorý poslucháč aktualizácie sa tiež nikdy stať nedostupná, ako poslucháč má silný odkaz na ňu.

Jediný spôsob, ako oddeliť ich dostupnosť je zmena poslucháčov, aby sa udržať len slabý odkaz na objekt sa aktualizuje. Upozorňujeme, že keď používate Cleaner namiesto finalize()sa FinalizeGuardian je zastaralé.

Kód bude vyzerať

public class PasteAction extends FocusedComponentAction {

    static FlavorListener createListener(WeakReference<PasteAction> r) {
        return event -> {
            PasteAction pa = r.get();
            if(pa != null) pa.updateEnabled();
        };
    }

    private static final Cleaner CLEANER = Cleaner.create();

    static void prepareCleanup(
                       Object referent, Clipboard clipboard, FlavorListener listener) {

        CLEANER.register(referent, () -> clipboard.removeFlavorListener(listener));
    }

    public PasteAction() {
        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        FlavorListener listener = createListener(new WeakReference<>(this));
        clipboard.addFlavorListener(listener);
        prepareCleanup(this, clipboard, listener);
    }

…

Upozorňujeme, že kritické časti boli umiestnené do static metódy, aby sa pri náhodnom zachytenie this odkaz nemožné. Tieto metódy získať minimálne potrebné robiť svoju prácu, createListener len prijíma slabý odkaz na opatrenia a prepareCleanup dostane ako referent Objectako čistenie akcie nesmie prístup k akémukoľvek členov činnosť, ale prijímať potrebné hodnoty ako samostatné parametre.

Ale po zobrazené, ako čistejšie používanie môže vyzerať, som pevne sa odradiť od pomocou tohto mechanizmu, najmä ako len čistenie mechanizmus. Tu, to nie je len ovplyvňujúce spotrebu pamäte, ale aj správanie sa programu, pretože, ako dlho, ako referencie neboli zúčtované, poslucháč bude neustále informovaní a udržať aktualizácia zastaralý objekt.

Od garbage collector je len vyvolaná pamäť potreby, je celkom možné, že to nefunguje, alebo nie je starostlivosť o týchto niekoľkých objektov, pretože tam nie je dostatok voĺnej pamäte, zatiaľ čo CPU je pod ťažkým bremenom, pretože veľa zastaralé poslucháčov je obsadené, ak chcete aktualizovať zastarané objekty (videl som takéto scenáre v praxi).

Aby toho nebolo málo, s súbežných zberateľov odpadkov, je dokonca možné, že ich zberu cyklu, opakovane sa prekrýva so skutočne zastarané výkon updateEnabled() vyvolaná poslucháč (pretože odkazoval nie je odstránená ešte). Ktoré budú aktívne brániť odpadkov zber týchto objektov, aj keď garbage collector beží a inak by zbierať je.

V skratke, ako je čistenie by sa nikdy nemali spoliehať na garbage collector.

2021-11-26 15:49:36

V iných jazykoch

Táto stránka je v iných jazykoch

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................