Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Android/art/art/test/2043-reference-pauses/src/   (Android Betriebssystem Version 17©)  Datei vom 26.5.2026 mit Größe 12 kB image not shown  

Quelle  Main.java

  Sprache: JAVA
 

/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.lang.ref.SoftReference;
import java.math.BigInteger;
import java.util.ArrayList;

/**
 * Basic test of WeakReferences with large amounts of memory that's only reachable through
 * finalizers. Also makes sure that finalizer-reachable data is not collected.
 * Can easily be modified to time Reference.get() blocking.
 */

public class Main {
    static final boolean PRINT_TIMES = false;  // true will cause benchmark failure.
    // Data structures repeatedly allocated in background to trigger GC.
    // Size of finalizer reachable trees.
    static final int TREE_HEIGHT = 15;  // Trees contain 2^TREE_HEIGHT -1 allocated objects.
    // Number of finalizable tree-owning objects that exist at one point.
    static final int N_RESURRECTING_OBJECTS = 10;
    // Number of short-lived, not finalizer-reachable, objects allocated between trees.
    static final int N_PLAIN_OBJECTS = 20_000;
    // Number of SoftReferences to CBTs we allocate.
    static final int N_SOFTREFS = 10;

    static final boolean BACKGROUND_GC_THREAD = true;
    static final int NBATCHES = 10;
    static final int NREFS = PRINT_TIMES ? 1_000_000 : 300_000;  // Multiple of NBATCHES.
    static final int REFS_PER_BATCH = NREFS / NBATCHES;

    static volatile boolean pleaseStop = false;

    // Large array of WeakReferences filled and accessed by tests below.
    ArrayList<WeakReference<Integer>> weakRefs = new ArrayList<>(NREFS);

    /**
     * Complete binary tree data structure. make(n) takes O(2^n) space.
     */

    static class CBT {
        CBT left;
        CBT right;
        CBT(CBT l, CBT r) {
            left = l;
            right = r;
        }
        static CBT make(int n) {
            if (n == 0) {
                return null;
            }
            return new CBT(make(n - 1), make(n - 1));
        }
        /**
         * Check that path described by bit-vector path has the correct length.
         */

        void check(int n, int path) {
            CBT current = this;
            for (int i = 0; i < n; i++, path = path >>> 1) {
                // Unexpectedly short paths result in NPE.
                if ((path & 1) == 0) {
                    current = current.left;
                } else {
                    current = current.right;
                }
            }
            if (current != null) {
                System.out.println("Complete binary tree path too long");
            }
        }
    }


    /**
     * A finalizable object that refers to O(2^TREE_HEIGHT) otherwise unreachable memory.
     * When finalized, it creates a new identical object, making sure that one always stays
     * around.
     */

    static class ResurrectingObject {
        CBT stuff;
        ResurrectingObject() {
            stuff = CBT.make(TREE_HEIGHT);
        }
        static ResurrectingObject a[] = new ResurrectingObject[2];
        static int i = 0;
        static synchronized void allocOne() {
            a[(++i) % 2] = new ResurrectingObject();
            // Check the previous one to make it hard to optimize anything out.
            if (i > 1) {
                a[(i + 1) % 2].stuff.check(TREE_HEIGHT, i /* weirdly interpreted as path */);
            }
        }
        protected void finalize() {
            stuff.check(TREE_HEIGHT, 42 /* Some path descriptor */);
            // Allocate a new one to replace this one.
            allocOne();
        }
    }

    void fillWeakRefs() {
        for (int i = 0; i < NREFS; ++i) {
             weakRefs.add(null);
        }
    }

    /*
     * Return maximum observed time in nanos to dereference a WeakReference to an unreachable
     * object. weakRefs is presumed to be pre-filled to have the correct size.
     */

    long timeUnreachableInner() {
        long maxNanos = 0;
        // Fill weakRefs with WeakReferences to unreachable integers, a batch at a time.
        // Then time and test .get() calls on carefully sampled array entries, some of which
        // will have been cleared.
        for (int i = 0; i < NBATCHES; ++i) {
            for (int j = 0; j < REFS_PER_BATCH; ++j) {
                weakRefs.set(i * REFS_PER_BATCH + j,
                        new WeakReference(new Integer(i * REFS_PER_BATCH + j)));
            }
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                System.out.println("Unexpected exception");
            }
            // Iterate over the filled-in section of weakRefs, but look only at a subset of the
            // elements, making sure the subsets for different top-level iterations are disjoint.
            // Otherwise the get() calls here will extend the lifetimes of the referents, and we
            // may never see any cleared WeakReferences.
            for (int j = (i + 1) * REFS_PER_BATCH - i - 1; j >= 0; j -= NBATCHES) {
                WeakReference<Integer> wr = weakRefs.get(j);
                if (wr != null) {
                    long startNanos = System.nanoTime();
                    Integer referent = wr.get();
                    long totalNanos = System.nanoTime() - startNanos;
                    if (referent == null) {
                        // Optimization to reduce max space use and scanning time.
                        weakRefs.set(j, null);
                    }
                    maxNanos = Math.max(maxNanos, totalNanos);
                    if (referent != null && referent.intValue() != j) {
                        System.out.println("Unexpected referent; expected " + j + " got "
                                + referent.intValue());
                    }
                }
            }
        }
        return maxNanos;
    }

    /*
     * Wrapper for the above that also checks that references were reclaimed.
     * We do this separately to make sure any stack references from the core of the
     * test are gone. Empirically, we otherwise sometimes see the zeroth WeakReference
     * not reclaimed.
     */

    long timeUnreachable() {
        long maxNanos = timeUnreachableInner();
        Runtime.getRuntime().gc();
        System.runFinalization();  // Presumed to wait for reference clearing.
        for (int i = 0; i < NREFS; ++i) {
            if (weakRefs.get(i) != null && weakRefs.get(i).get() != null) {
                System.out.println("WeakReference to " + i + " wasn't cleared");
            }
        }
        return maxNanos;
    }

    /**
     * Return maximum observed time in nanos to dereference a WeakReference to a reachable
     * object. Overwrites weakRefs, which is presumed to have NREFS entries already.
    */

    long timeReachable() {
        long maxNanos = 0;
        // Similar to the above, but we use WeakReferences to otherwise reachable objects,
        // which should thus not get cleared.
        Integer[] strongRefs = new Integer[NREFS];
        for (int i = 0; i < NBATCHES; ++i) {
            for (int j = i * REFS_PER_BATCH; j < (i + 1) * REFS_PER_BATCH; ++j) {
                Integer newObj = new Integer(j);
                strongRefs[j] = newObj;
                weakRefs.set(j, new WeakReference(newObj));
            }
            for (int j = (i + 1) * REFS_PER_BATCH - 1; j >= 0; --j) {
                WeakReference<Integer> wr = weakRefs.get(j);
                long startNanos = System.nanoTime();
                Integer referent = wr.get();
                long totalNanos = System.nanoTime() - startNanos;
                maxNanos = Math.max(maxNanos, totalNanos);
                if (referent == null) {
                    System.out.println("Unexpectedly cleared referent at " + j);
                } else if (referent.intValue() != j) {
                    System.out.println("Unexpected reachable referent; expected " + j + " got "
                            + referent.intValue());
                }
            }
        }
        Reference.reachabilityFence(strongRefs);
        return maxNanos;
    }

    void runTest() {
        System.out.println("Starting");
        fillWeakRefs();
        long unreachableNanos = timeUnreachable();
        if (PRINT_TIMES) {
            System.out.println("Finished timeUnrechable()");
        }
        long reachableNanos = timeReachable();
        String unreachableMillis =
                String. format("%,.3f", ((double) unreachableNanos) / 1_000_000);
        String reachableMillis =
                String. format("%,.3f", ((double) reachableNanos) / 1_000_000);
        if (PRINT_TIMES) {
            System.out.println(
                    "Max time for WeakReference.get (unreachable): " + unreachableMillis);
            System.out.println(
                    "Max time for WeakReference.get (reachable): " + reachableMillis);
        }
        // Only report extremely egregious pauses to avoid spurious failures.
        if (unreachableNanos > 10_000_000_000L) {
            System.out.println("WeakReference.get (unreachable) time unreasonably long");
        }
        if (reachableNanos > 10_000_000_000L) {
            System.out.println("WeakReference.get (reachable) time unreasonably long");
        }
    }

    /**
     * Allocate and GC a lot, while keeping significant amounts of finalizer and
     * SoftReference-reachable memory around.
     */

    static Runnable allocFinalizable = new Runnable() {
        public void run() {
            // Allocate and drop some finalizable objects that take a long time
            // to mark. Designed to be hard to optimize away. Each of these objects will
            // build a new one in its finalizer before really going away.
            ArrayList<SoftReference<CBT>> softRefs = new ArrayList<>(N_SOFTREFS);
            for (int i = 0; i < N_SOFTREFS; ++i) {
                // These should not normally get reclaimed, since we shouldn't run out of
                // memory. They do increase tracing time.
                softRefs.add(new SoftReference(CBT.make(TREE_HEIGHT)));
            }
            for (int i = 0; i < N_RESURRECTING_OBJECTS; ++i) {
                ResurrectingObject.allocOne();
            }
            BigInteger counter = BigInteger.ZERO;
            for (int i = 1; !pleaseStop; ++i) {
                // Allocate a lot of short-lived objects, using BigIntegers to minimize the chance
                // of the allocation getting optimized out. This makes things slightly more
                // realistic, since not all objects will be finalizer reachable.
                for (int j = 0; j < N_PLAIN_OBJECTS / 2; ++j) {
                    counter = counter.add(BigInteger.TEN);
                }
                // Look at counter to reduce chance of optimizing out the allocation.
                if (counter.longValue() % 10 != 0) {
                    System.out.println("Bad allocFinalizable counter value: " + counter);
                }
                // Explicitly collect here, mostly to prevent heap growth. Otherwise we get
                // ahead of the GC and eventually block on it.
                Runtime.getRuntime().gc();
                if (PRINT_TIMES && i % 100 == 0) {
                    System.out.println("Collected " + i + " times");
                }
            }
            // To be safe, access softRefs.
            final CBT sample = softRefs.get(N_SOFTREFS / 2).get();
            if (sample != null) {
              sample.check(TREE_HEIGHT, 47 /* some path descriptor */);
            }
        }
    };

    public static void main(String[] args) throws Exception {
        Main theTest = new Main();
        Thread allocThread = null;
        if (BACKGROUND_GC_THREAD) {
            allocThread = new Thread(allocFinalizable);
            allocThread.setDaemon(true);  // Terminate if main thread dies.
            allocThread.start();
        }
        theTest.runTest();
        if (BACKGROUND_GC_THREAD) {
            pleaseStop = true;
            allocThread.join();
        }
        System.out.println("Finished");
    }
}

Messung V0.5 in Prozent
C=93 H=93 G=92

¤ Dauer der Verarbeitung: 0.2 Sekunden  (vorverarbeitet am  2026-06-29) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.