| /* |
| * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| * |
| */ |
| |
| #ifndef SHARE_GC_SHARED_STRINGDEDUP_STRINGDEDUP_HPP |
| #define SHARE_GC_SHARED_STRINGDEDUP_STRINGDEDUP_HPP |
| |
| // String Deduplication |
| // |
| // String deduplication aims to reduce the heap live-set by modifying equal |
| // instances of java.lang.String so they share the same backing byte array |
| // (the String's value). |
| // |
| // The deduplication process is divided in two main parts, 1) finding the |
| // objects to deduplicate, and 2) deduplicating those objects. |
| // |
| // The first part is done as part of a normal GC cycle when objects are |
| // marked or evacuated. At this time a check is applied on each object to |
| // determine whether it is a candidate for deduplication. Candidates are |
| // added to the set of deduplication requests for later processing. |
| // |
| // The second part, processing the deduplication requests, is a concurrent |
| // phase. This phase is executed by the deduplication thread, which takes |
| // candidates from the set of requests and tries to deduplicate them. |
| // |
| // A deduplication table is used to keep track of unique byte arrays used by |
| // String objects. When deduplicating, a lookup is made in this table to |
| // see if there is already an equivalent byte array that was used by some |
| // other String. If so, the String object is adjusted to point to that byte |
| // array, and the original array is released, allowing it to eventually be |
| // garbage collected. If the lookup fails the byte array is instead |
| // inserted into the table so it can potentially be shared with other |
| // Strings in the future. |
| // |
| // The set of requests uses entries from a pair of weak OopStorage objects. |
| // One is used for requests, the other is being processed. When processing |
| // completes, the roles of the storage objects are exchanged. The GC adds |
| // entries referring to discovered candidates, allocating new OopStorage |
| // entries for the requests. The deduplication processing thread does a |
| // concurrent iteration over the processing storage, deduplicating the |
| // Strings and releasing the OopStorage entries. Two storage objects are |
| // used so there isn't any conflict between adding and removing entries by |
| // different threads. |
| // |
| // The deduplication table uses entries from another weak OopStorage to hold |
| // the byte arrays. This permits reclamation of arrays that become unused. |
| // This is separate from the request storage objects because dead count |
| // tracking is used by the table implementation as part of resizing |
| // decisions and for deciding when to cleanup dead entries in the table. |
| // The usage pattern for the table is also very different from that of the |
| // request storages. The request/processing storages are used in a way that |
| // supports bulk allocation and release of entries. |
| // |
| // Candidate selection criteria is GC specific. This class provides some |
| // helper functions that may be of use when implementing candidate |
| // selection. |
| // |
| // Strings interned in the StringTable require special handling. Once a |
| // String has been added to the StringTable, its byte array must not change. |
| // Doing so would counteract C2 optimizations on string literals. But an |
| // interned string might later become a deduplication candidate through the |
| // normal GC discovery mechanism. To prevent such modifications, the |
| // deduplication_forbidden flag of a String is set before interning it. A |
| // String with that flag set may have its byte array added to the |
| // deduplication table, but will not have its byte array replaced by a |
| // different but equivalent array from the table. |
| // |
| // A GC must opt-in to support string deduplication. This primarily involves |
| // making deduplication requests. As the GC is processing objects it must |
| // determine which are candidates for deduplication, and add those objects |
| // to StringDedup::Requests objects. Typically, each GC marking/evacuation |
| // thread has its own Requests object. Once liveness analysis is complete, |
| // but before weak reference processing, the GC should flush or delete all |
| // of its Requests objects. |
| // |
| // The deduplication thread is a daemon JavaThread. No thread visitor is |
| // needed, as it is handled via the normal JavaThread visiting mechanism. |
| // Similarly, there is no need for a stop() function. |
| // |
| // For additional information on string deduplication, please see JEP 192, |
| // https://openjdk.org/jeps/192 |
| |
| #include "memory/allocation.hpp" |
| #include "memory/allStatic.hpp" |
| #include "oops/oopsHierarchy.hpp" |
| #include "utilities/globalDefinitions.hpp" |
| |
| class Klass; |
| class StringDedupThread; |
| class ThreadClosure; |
| |
| // The StringDedup class provides the API for the deduplication mechanism. |
| // StringDedup::Requests and the StringDedup functions for candidate testing |
| // are all that a GC needs to use to support the string deduplication |
| // feature. Other functions in the StringDedup class are called where |
| // needed, without requiring GC-specific code. |
| class StringDedup : public AllStatic { |
| friend class StringDedupThread; |
| |
| class Config; |
| class Processor; |
| class Stat; |
| class StorageUse; |
| class Table; |
| |
| static bool _initialized; |
| static bool _enabled; |
| |
| static Processor* _processor; |
| static Stat _cur_stat; |
| static Stat _total_stat; |
| |
| static const Klass* _string_klass_or_null; |
| static uint _enabled_age_threshold; |
| static uint _enabled_age_limit; |
| |
| public: |
| class Requests; |
| |
| // Initialize and check command line arguments. |
| // Returns true if configuration is valid, false otherwise. |
| static bool ergo_initialize(); |
| |
| // Initialize deduplication if enabled by command line arguments. |
| static void initialize(); |
| |
| // Returns true if string deduplication is enabled. |
| static bool is_enabled() { return _enabled; } |
| |
| // Create and start the deduplication processor thread. |
| // precondition: is_enabled() |
| static void start(); |
| |
| // Marks the String as not being subject to deduplication. This can be |
| // used to prevent deduplication of Strings whose value array must remain |
| // stable and cannot be replaced by a shared duplicate. Must be called |
| // before obtaining the value array; this function provides an acquire |
| // barrier. |
| // precondition: is_enabled() |
| // precondition: java_string is a Java String object. |
| static void forbid_deduplication(oop java_string); |
| |
| // Notify that a String is being added to the StringTable. |
| // Implicitly forbids deduplication of the String. |
| // precondition: is_enabled() |
| // precondition: java_string is a Java String object. |
| static void notify_intern(oop java_string); |
| |
| // precondition: at safepoint |
| static void verify(); |
| |
| // Some predicates for use in testing whether an object is a candidate for |
| // deduplication. These functions combine an implicit is_enabled check |
| // with another check in a single comparison. |
| |
| // Return true if k is String klass and deduplication is enabled. |
| static bool is_enabled_string(const Klass* k) { |
| return k == _string_klass_or_null; |
| } |
| |
| // Return true if age == StringDeduplicationAgeThreshold and |
| // deduplication is enabled. |
| static bool is_threshold_age(uint age) { |
| // Threshold is from option if enabled, or an impossible value (exceeds |
| // markWord::max_age) if disabled. |
| return age == _enabled_age_threshold; |
| } |
| |
| // Return true if age < StringDeduplicationAgeThreshold and |
| // deduplication is enabled. |
| static bool is_below_threshold_age(uint age) { |
| // Limit is from option if enabled, or 0 if disabled. |
| return age < _enabled_age_limit; |
| } |
| }; |
| |
| // GC requests for String deduplication. |
| // |
| // Each marking thread should have it's own Requests object. When marking |
| // is completed the Requests object must be flushed (either explicitly or by |
| // the destructor). |
| class StringDedup::Requests : public CHeapObj<mtGC> { |
| StorageUse* _storage_for_requests; |
| oop** _buffer; |
| size_t _index; |
| bool _refill_failed; |
| |
| bool refill_buffer(); |
| |
| public: |
| Requests(); |
| ~Requests(); // Calls flush(). |
| |
| // Request deduplication of java_string. |
| // prerequisite: StringDedup::is_enabled() |
| // prerequisite: java_string is a Java String |
| void add(oop java_string); |
| |
| // Flush any buffered deduplication requests and release resources |
| // used by this object. |
| void flush(); |
| }; |
| |
| #endif // SHARE_GC_SHARED_STRINGDEDUP_STRINGDEDUP_HPP |