From 7ab95e398c95e10307f5ccb78488b7c976f0caef Mon Sep 17 00:00:00 2001 From: Michael Bien Date: Sun, 29 Mar 2026 07:43:12 +0200 Subject: [PATCH 1/3] InstalledFileLocatorImpl: avoid recompiling regex in hot code clusterFor() is called often during startup and flamegraph showed that the regex pattern as bottleneck. -> implement the dynamic part of the regex by hand so that the constant part can be put in a static field. --- .../startup/InstalledFileLocatorImpl.java | 116 ++++++++++-------- 1 file changed, 66 insertions(+), 50 deletions(-) diff --git a/platform/core.startup/src/org/netbeans/core/startup/InstalledFileLocatorImpl.java b/platform/core.startup/src/org/netbeans/core/startup/InstalledFileLocatorImpl.java index 6bf4f802d757..c0a497abf9a8 100644 --- a/platform/core.startup/src/org/netbeans/core/startup/InstalledFileLocatorImpl.java +++ b/platform/core.startup/src/org/netbeans/core/startup/InstalledFileLocatorImpl.java @@ -26,7 +26,6 @@ import java.io.FileReader; import java.io.IOException; import java.io.InputStream; -import java.io.Reader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -62,7 +61,7 @@ public final class InstalledFileLocatorImpl extends InstalledFileLocator { private final File[] dirs; public InstalledFileLocatorImpl() { List _dirs = computeDirs(); - dirs = _dirs.toArray(new File[0]); + dirs = _dirs.toArray(File[]::new); } private static void addDir(List _dirs, String d) { @@ -99,41 +98,42 @@ private static void addDir(List _dirs, String d) { */ public static synchronized void prepareCache() { assert fileCache == null; - fileCache = new HashMap>>(); - clusterCache = new HashMap>(); + fileCache = new HashMap<>(); + clusterCache = new HashMap<>(); try { InputStream is = Stamps.getModulesJARs().asStream("all-files.dat"); if (is == null) { return; } - DataInputStream dis = new DataInputStream(is); - int filesSize = dis.readInt(); - for (int i = 0; i < filesSize; i++) { - String key = dis.readUTF(); - Map> fileToKids = new HashMap>(); - int filesToKids = dis.readInt(); - for (int j = 0; j < filesToKids; j++) { - final String read = RelPaths.readRelativePath(dis); - File f = new File(read); - int kidsSize = dis.readInt(); - List kids = new ArrayList(kidsSize); - for (int k = 0; k < kidsSize; k++) { - kids.add(dis.readUTF()); + try (DataInputStream dis = new DataInputStream(is)) { + int filesSize = dis.readInt(); + for (int i = 0; i < filesSize; i++) { + String key = dis.readUTF(); + Map> fileToKids = new HashMap<>(); + int filesToKids = dis.readInt(); + for (int j = 0; j < filesToKids; j++) { + final String read = RelPaths.readRelativePath(dis); + File f = new File(read); + int kidsSize = dis.readInt(); + List kids = new ArrayList<>(kidsSize); + for (int k = 0; k < kidsSize; k++) { + kids.add(dis.readUTF()); + } + fileToKids.put(f, new HashSet<>(kids)); } - fileToKids.put(f, new HashSet(kids)); + fileCache.put(key, fileToKids); } - fileCache.put(key, fileToKids); - } - int clusterSize = dis.readInt(); - for (int i = 0; i < clusterSize; i++) { - String key = dis.readUTF(); - int valueSize = dis.readInt(); - List values = new ArrayList(valueSize); - for (int j = 0; j < valueSize; j++) { - values.add(new File(RelPaths.readRelativePath(dis))); + int clusterSize = dis.readInt(); + for (int i = 0; i < clusterSize; i++) { + String key = dis.readUTF(); + int valueSize = dis.readInt(); + List values = new ArrayList<>(valueSize); + for (int j = 0; j < valueSize; j++) { + values.add(new File(RelPaths.readRelativePath(dis))); + } + clusterCache.put(key, values); } - clusterCache.put(key, values); } } catch (IOException ex) { LOG.log(Level.INFO, null, ex); @@ -242,7 +242,7 @@ private Set doLocate(String relativePath, boolean localized, boolean singl } else if (files == null) { files = f; } else { - files = new LinkedHashSet(files); + files = new LinkedHashSet<>(files); files.addAll(f); } } @@ -267,11 +267,11 @@ private Set locateExactPath(String prefix, String name, boolean single, St assert owned(codeNameBase, dir, path); File f = makeFile(dir, path); if (single) { - return Collections.singleton(f); + return Set.of(f); } else if (files == null) { - files = Collections.singleton(f); + files = Set.of(f); } else { - files = new LinkedHashSet(files); + files = new LinkedHashSet<>(files); files.add(f); } } @@ -282,11 +282,11 @@ private Set locateExactPath(String prefix, String name, boolean single, St if (f.exists()) { assert owned(codeNameBase, dir, path); if (single) { - return Collections.singleton(f); + return Set.of(f); } else if (files == null) { - files = Collections.singleton(f); + files = Set.of(f); } else { - files = new LinkedHashSet(files); + files = new LinkedHashSet<>(files); files.add(f); } } @@ -301,14 +301,14 @@ private List clustersFor(String codeNameBase, String path) { return Arrays.asList(dirs); } String codeNameBaseDashes = codeNameBase.replace('.', '-'); - if (path.matches("(modules/(locale/)?)?" + codeNameBaseDashes + "(_[^/]+)?[.]jar")) { // NOI18N + if (isBaseInPath(codeNameBaseDashes, path)) { // Called very commonly during startup; cannot afford to do exact check each time. // Anyway if the module is there it is almost certainly installed in the same cluster. return Arrays.asList(dirs); } List clusters = clusterCache != null ? clusterCache.get(codeNameBase) : null; if (clusters == null) { - clusters = new ArrayList(1); + clusters = new ArrayList<>(1); String rel = "update_tracking/" + codeNameBaseDashes + ".xml"; // NOI18N for (File dir : dirs) { File tracking = new File(dir, rel); @@ -331,8 +331,29 @@ private List clustersFor(String codeNameBase, String path) { return clusters; } + private static final Pattern TAIL = Pattern.compile("(_[^/]+)?[.]jar"); // NOI18N + + // hot section: avoids recompiling the pattern by unrolling the prefix manually + private static boolean isBaseInPath(String codeNameBaseDashes, String path) { +// return path.matches("(modules/(locale/)?)?" + codeNameBaseDashes + "(_[^/]+)?[.]jar"); + int pos = 0; + if (path.startsWith("modules/")) { // NOI18N + pos += "modules/".length(); // NOI18N + if (path.startsWith("locale/", pos)) { // NOI18N + pos += "locale/".length(); // NOI18N + } + } + if (path.startsWith(codeNameBaseDashes, pos)) { + pos += codeNameBaseDashes.length(); + if (TAIL.matcher(path.substring(pos)).matches()) { + return true; + } + } + return false; + } + private static String[] prefixAndName(String relativePath) { - if (relativePath.length() == 0) { + if (relativePath.isEmpty()) { throw new IllegalArgumentException("Cannot look up \"\" in InstalledFileLocator.locate"); // NOI18N } if (relativePath.charAt(0) == '/') { @@ -359,7 +380,7 @@ private Map> fileCachePerPrefix(String prefix) { assert Thread.holdsLock(InstalledFileLocatorImpl.class); Map> fileCachePerPrefix = fileCache.get(prefix); if (fileCachePerPrefix == null) { - fileCachePerPrefix = new HashMap>(dirs.length * 2); + fileCachePerPrefix = new HashMap<>(dirs.length * 2); for (int i = 0; i < dirs.length; i++) { File root = dirs[i]; File d; @@ -375,7 +396,7 @@ private Map> fileCachePerPrefix(String prefix) { if (isDir) { String[] kids = d.list(); if (kids != null) { - fileCachePerPrefix.put(root, new HashSet(Arrays.asList(kids))); + fileCachePerPrefix.put(root, new HashSet<>(Arrays.asList(kids))); } else { Util.err.log(Level.WARNING, "could not read files in {0} at {1}", new Object[] {d, findCaller()}); } @@ -419,7 +440,7 @@ private static synchronized boolean owned(String codeNameBase, File dir, String LOG.log(Level.FINE, "No update tracking found in {0}", dir); return true; } - ownershipByModule = new HashMap>(); + ownershipByModule = new HashMap<>(); ownershipByModuleByCluster.put(dir, ownershipByModule); } Set ownership = ownershipByModule.get(codeNameBase); @@ -429,15 +450,13 @@ private static synchronized boolean owned(String codeNameBase, File dir, String LOG.log(Level.WARNING, "no such module {0} at {1}", new Object[] {list, findCaller()}); return true; } - ownership = new HashSet(); + ownership = new HashSet<>(); try { // Could do a proper XML parse but likely too slow. if (LOG.isLoggable(Level.FINE)) { LOG.log(Level.FINE, "Parsing {0} due to {1}", new Object[] {list, path}); } - Reader r = new FileReader(list); - try { - BufferedReader br = new BufferedReader(r); + try (BufferedReader br = new BufferedReader(new FileReader(list))) { String line; while ((line = br.readLine()) != null) { Matcher m = FILE_PATTERN.matcher(line); @@ -445,9 +464,6 @@ private static synchronized boolean owned(String codeNameBase, File dir, String ownership.add(m.group(1)); } } - br.close(); - } finally { - r.close(); } } catch (IOException x) { LOG.log(Level.INFO, "could not parse " + list, x); @@ -476,7 +492,7 @@ private static synchronized boolean owned(String codeNameBase, File dir, String return true; } private static final Pattern FILE_PATTERN = Pattern.compile("\\s*"); - private static final Map>> ownershipByModuleByCluster = new HashMap>>(); + private static final Map>> ownershipByModuleByCluster = new HashMap<>(); private static String findCaller() { for (StackTraceElement line : Thread.currentThread().getStackTrace()) { @@ -492,7 +508,7 @@ private static synchronized void scheduleSave() { } static List computeDirs() { - List _dirs = new ArrayList(); + List _dirs = new ArrayList<>(); addDir(_dirs, System.getProperty("netbeans.user")); // NOI18N String nbdirs = System.getProperty("netbeans.dirs"); // #27151 if (nbdirs != null) { From 1fa4b2bf2cb2b7cc153227f653122dd0763d8656 Mon Sep 17 00:00:00 2001 From: Michael Bien Date: Sun, 29 Mar 2026 07:54:11 +0200 Subject: [PATCH 2/3] NbInstaller hidden pkg and deprecated module computation optimizations - avoid loading all (~700) modules into TreeMap - use 0 copy Module#getDependenciesArray for iteration instead of Set - code renovations --- .../netbeans/core/startup/NbInstaller.java | 165 ++++++++---------- .../core/startup/NbInstallerCacheTest.java | 4 +- 2 files changed, 70 insertions(+), 99 deletions(-) diff --git a/platform/core.startup/src/org/netbeans/core/startup/NbInstaller.java b/platform/core.startup/src/org/netbeans/core/startup/NbInstaller.java index cd6616c44a34..7e260c008c64 100644 --- a/platform/core.startup/src/org/netbeans/core/startup/NbInstaller.java +++ b/platform/core.startup/src/org/netbeans/core/startup/NbInstaller.java @@ -38,7 +38,6 @@ import java.util.Properties; import java.util.Set; import java.util.StringTokenizer; -import java.util.TreeMap; import java.util.TreeSet; import java.util.jar.Attributes; import java.util.jar.JarEntry; @@ -79,11 +78,11 @@ final class NbInstaller extends ModuleInstaller { private static final Logger LOG = Logger.getLogger(NbInstaller.class.getName()); /** set of manifest sections for each module */ - private final Map> sections = new HashMap>(100); + private final Map> sections = new HashMap<>(100); /** ModuleInstall classes for each module that declares one */ - private final Map> installs = new HashMap>(100); + private final Map> installs = new HashMap<>(100); /** layer resources for each module that declares one */ - private final Map layers = new HashMap(100); + private final Map layers = new HashMap<>(100); /** exact use of this is hard to explain */ private boolean initializedFolderLookup = false; /** where to report events to */ @@ -93,13 +92,13 @@ final class NbInstaller extends ModuleInstaller { /** associated manager */ private ModuleManager mgr; /** set of permitted core or package dependencies from a module */ - private final Map> kosherPackages = new HashMap>(100); + private final Map> kosherPackages = new HashMap<>(100); /** classpath ~ JRE packages to be hidden from a module */ - private final Map> hiddenClasspathPackages = new HashMap>(); + private final Map> hiddenClasspathPackages = new HashMap<>(); /** #164510: similar to {@link #hiddenClasspathPackages} but backwards for efficiency */ - private final Map> hiddenClasspathPackagesReverse = new HashMap>(); + private final Map> hiddenClasspathPackagesReverse = new HashMap<>(); /** caches important values from module manifests */ - private final Cache cache = new Cache(); + private final ManifestCache cache = new ManifestCache(); /** Processing @OnStart/@OnStop calls */ private final NbStartStop onStartStop = new NbStartStop(null, null); @@ -141,7 +140,7 @@ public void prepare(Module m) throws InvalidException { ManifestSection section = ManifestSection.create(entry.getKey(), entry.getValue(), m); if (section != null) { if (mysections == null) { - mysections = new HashSet(25); + mysections = new HashSet<>(25); } mysections.add(section); } @@ -192,11 +191,7 @@ public void prepare(Module m) throws InvalidException { } if (c == Object.class) throw new ClassCastException("Should extend ModuleInstall: " + clazz.getName()); // NOI18N // Did not find any validate() method, so remember the class and resolve later. - } catch (Exception t) { - InvalidException ie = new InvalidException(m, t.toString()); - ie.initCause(t); - throw ie; - } catch (LinkageError t) { + } catch (Exception | LinkageError t) { InvalidException ie = new InvalidException(m, t.toString()); ie.initCause(t); throw ie; @@ -227,12 +222,12 @@ public void prepare(Module m) throws InvalidException { } private void checkForHiddenPackages(Module m) throws InvalidException { - List hiddenPackages = new ArrayList(); - List mWithDeps = new LinkedList(); + List hiddenPackages = new ArrayList<>(); + List mWithDeps = new LinkedList<>(); mWithDeps.add(m); if (mgr != null) { addEnabledFragments(m, mWithDeps); - for (Dependency d : m.getDependencies()) { + for (Dependency d : m.getDependenciesArray()) { if (d.getType() == Dependency.TYPE_MODULE) { Module _m = mgr.get((String) Util.parseCodeName(d.getName())[0]); assert _m != null : d; @@ -273,11 +268,8 @@ private void checkForHiddenPackages(Module m) throws InvalidException { synchronized (hiddenClasspathPackages) { hiddenClasspathPackages.put(m, hiddenPackages); for (Module.PackageExport pkg : hiddenPackages) { - List ms = hiddenClasspathPackagesReverse.get(pkg); - if (ms == null) { - hiddenClasspathPackagesReverse.put(pkg, ms = new LinkedList()); - } - ms.add(m); + hiddenClasspathPackagesReverse.computeIfAbsent(pkg, k -> new LinkedList<>()) + .add(m); } } } @@ -291,6 +283,7 @@ private void addEnabledFragments(Module forModule, List moduleWithDepend } } + @Override public void dispose(Module m) { Util.err.fine("dispose: " + m); // Events probably not needed here. @@ -350,10 +343,8 @@ private void loadImpl(List modules) { for (Module m: modules) { try { loadSections(m, true); - } catch (Exception t) { + } catch (Exception | LinkageError t) { Util.err.log(Level.SEVERE, null, t); - } catch (LinkageError le) { - Util.err.log(Level.SEVERE, null, le); } ev.log(Events.PERF_TICK, "sections for " + m.getCodeName() + " loaded"); // NOI18N } @@ -376,12 +367,8 @@ private void loadImpl(List modules) { for (Module m: modules) { try { loadCode(m, true); - } catch (Exception t) { + } catch (Exception | LinkageError | AssertionError t) { Util.err.log(Level.SEVERE, null, t); - } catch (LinkageError le) { - Util.err.log(Level.SEVERE, null, le); - } catch (AssertionError e) { - Util.err.log(Level.SEVERE, null, e); } ev.log(Events.PERF_TICK, "ModuleInstall for " + m.getCodeName() + " called"); // NOI18N } @@ -403,11 +390,8 @@ final void preloadCache(Collection modules) { @Override public void unload(final List modules) { - FileUtil.runAtomicAction(new Runnable() { - @Override - public void run() { - unloadImpl(modules); - } + FileUtil.runAtomicAction((Runnable) () -> { + unloadImpl(modules); }); } @@ -416,10 +400,8 @@ private void unloadImpl(List modules) { for (Module m: modules) { try { loadCode(m, false); - } catch (Exception t) { + } catch (Exception | LinkageError t) { Util.err.log(Level.SEVERE, null, t); - } catch (LinkageError le) { - Util.err.log(Level.SEVERE, null, le); } } CoreBridge.getDefault().loaderPoolTransaction(true); @@ -427,10 +409,8 @@ private void unloadImpl(List modules) { for (Module m: modules) { try { loadSections(m, false); - } catch (Exception t) { + } catch (Exception | LinkageError t) { Util.err.log(Level.SEVERE, null, t); - } catch (LinkageError le) { - Util.err.log(Level.SEVERE, null, le); } } } finally { @@ -515,6 +495,7 @@ private void loadGenericSection(ManifestSection s, boolean load) { private final InstanceContent.Convertor convertor = new Convertor(); private final class Convertor implements InstanceContent.Convertor { // or ? Convertor() {} + @Override public Object convert(ManifestSection s) { try { return s.getInstance(); @@ -528,6 +509,7 @@ public Object convert(ManifestSection s) { return null; } } + @Override public Class type(ManifestSection s) { return s.getSuperclass(); } @@ -536,6 +518,7 @@ public Class type(ManifestSection s) { * @param obj the registered object * @return the ID for the object */ + @Override public String id(ManifestSection obj) { return obj.toString (); } @@ -544,6 +527,7 @@ public String id(ManifestSection obj) { * @param obj the registered object * @return the name representing the object for the user */ + @Override public String displayName(ManifestSection obj) { return obj.toString (); } @@ -558,13 +542,13 @@ public String displayName(ManifestSection obj) { void loadLayers(List modules, boolean load) { ev.log(load ? Events.LOAD_LAYERS : Events.UNLOAD_LAYERS, modules); // #23609: dependent modules should be able to override: - modules = new ArrayList(modules); + modules = new ArrayList<>(modules); Collections.reverse(modules); - Map> urls = new HashMap>(5); + Map> urls = new HashMap<>(5); ModuleLayeredFileSystem userModuleLayer = ModuleLayeredFileSystem.getUserModuleLayer(); ModuleLayeredFileSystem installationModuleLayer = ModuleLayeredFileSystem.getInstallationModuleLayer(); - urls.put(userModuleLayer, new LinkedHashSet(1000)); - urls.put(installationModuleLayer, new LinkedHashSet(1000)); + urls.put(userModuleLayer, new LinkedHashSet<>(1000)); + urls.put(installationModuleLayer, new LinkedHashSet<>(1000)); for (Module m: modules) { // #19458: only put reloadables into the "session layer" // (where they will not have their layers cached). All others @@ -573,7 +557,7 @@ void loadLayers(List modules, boolean load) { ModuleLayeredFileSystem host = m.isReloadable() ? userModuleLayer : installationModuleLayer; Collection theseurls = urls.get(host); if (theseurls == null) { - theseurls = new LinkedHashSet(1000); + theseurls = new LinkedHashSet<>(1000); urls.put(host, theseurls); } String s = layers.get(m); @@ -644,19 +628,15 @@ void loadLayers(List modules, boolean load) { * @param modules the modules which are now being turned on */ private void checkForDeprecations(List modules) { - Map> depToUsers = new TreeMap>(); + Map> depToUsers = new HashMap<>(700); for (Module m : modules) { String depr = cache.findProperty(m, "OpenIDE-Module-Deprecated", false); // NOI18N if (!Boolean.parseBoolean(depr)) { - for (Dependency dep : m.getDependencies()) { + for (Dependency dep : m.getDependenciesArray()) { if (dep.getType() == Dependency.TYPE_MODULE) { String cnb = (String) Util.parseCodeName(dep.getName())[0]; - Set users = depToUsers.get(cnb); - if (users == null) { - users = new TreeSet(); - depToUsers.put(cnb, users); - } - users.add(m.getCodeNameBase()); + depToUsers.computeIfAbsent(cnb, k -> new HashSet<>()) + .add(m.getCodeNameBase()); } } } @@ -670,7 +650,7 @@ private void checkForDeprecations(List modules) { String message = cache.findProperty(o, "OpenIDE-Module-Deprecation-Message", true); // NOI18N // XXX use NbEvents? I18N? // For now, assume this is a developer-oriented message that need not be localized or displayed in a pretty fashion. - Set users = entry.getValue(); + Set users = new TreeSet<>(entry.getValue()); if (message != null) { Util.err.log(Level.WARNING, "the modules {0} use {1} which is deprecated: {2}", new Object[] {users, dep, message}); } else { @@ -680,6 +660,7 @@ private void checkForDeprecations(List modules) { } } + @Override public boolean closing(List modules) { Util.err.fine("closing: " + modules); for (Module m: modules) { @@ -691,11 +672,9 @@ public boolean closing(List modules) { Util.err.fine("Module " + m + " refused to close"); return false; } - } catch (RuntimeException re) { + } catch (RuntimeException | LinkageError re) { Util.err.log(Level.SEVERE, null, re); // continue, assume it is trash - } catch (LinkageError le) { - Util.err.log(Level.SEVERE, null, le); } } } @@ -724,8 +703,6 @@ public Task closeAsync(List modules) { ModuleInstall inst = SharedClassObject.findObject(instClazz, true); if (inst == null) throw new IllegalStateException("Inconsistent state: " + instClazz); // NOI18N inst.close(); - } catch (ThreadDeath td) { - throw td; } catch (Throwable t) { // Catch even the heavy stuff here, we are going away. Util.err.log(Level.SEVERE, null, t); @@ -783,7 +760,7 @@ static void register(String name, Object obj) { arr.add("org.openide.modules.ModuleFormat1"); // NOI18N arr.add("org.openide.modules.ModuleFormat2"); // NOI18N - return arr.toArray (new String[0]); + return arr.toArray(String[]::new); } return null; } @@ -883,11 +860,11 @@ private boolean checkBootDelegation(String pkg) { private Set findKosher(Module m) { Set s = kosherPackages.get(m); if (s == null) { - s = new HashSet(); + s = new HashSet<>(); Set deps = m.getDependencies(); SpecificationVersion openide = Util.getModuleDep(deps, "org.openide"); // NOI18N boolean pre27853 = (openide == null || openide.compareTo(new SpecificationVersion("1.3.12")) < 0); // NOI18N - for (Dependency dep : deps) { + for (Dependency dep : m.getDependenciesArray()) { // Extend this for other classpath modules: if (dep.getType() == Dependency.TYPE_MODULE && dep.getName().equals("org.netbeans.core.startup/1")) { // NOI18N @@ -972,7 +949,7 @@ String getEffectiveClasspath(Module m) { return ""; // NOI18N } // The classpath entries - each is a filename possibly followed by package qualifications. - List l = new ArrayList(100); + List l = new ArrayList<>(100); // Start with boot classpath. createBootClassPath(l); // Move on to "startup classpath", qualified by applicable package deps etc. @@ -989,11 +966,11 @@ String getEffectiveClasspath(Module m) { } // Finally include this module and its dependencies recursively. // Modules whose direct classpath has already been added to the list: - Set modulesConsidered = new HashSet(50); + Set modulesConsidered = new HashSet<>(50); // Code names of modules on which this module has an impl dependency // (so can use any package): - Set implDeps = new HashSet(10); - for (Dependency dep : m.getDependencies()) { + Set implDeps = new HashSet<>(10); + for (Dependency dep : m.getDependenciesArray()) { // Remember, provide-require deps do not affect classpath! if (dep.getType() == Dependency.TYPE_MODULE && dep.getComparison() == Dependency.COMPARE_IMPL) { // We can assume the impl dep has the correct version; @@ -1102,7 +1079,7 @@ private static void addStartupClasspathEntry(File cpEntry, List cp, Set< private void addModuleClasspathEntries(Module m, Module orig, Set considered, Set implDeps, List cp, int depth) { // Head recursion so that baser modules are added to the front of the classpath: if (!considered.add(m)) return; - for (Dependency dep : m.getDependencies()) { + for (Dependency dep : m.getDependenciesArray()) { if (dep.getType() == Dependency.TYPE_MODULE) { String cnb = (String) Util.parseCodeName(dep.getName())[0]; Module next = mgr.get(cnb); @@ -1156,31 +1133,26 @@ private void preresolveClasses(List modules) { if (m.getJarFile() == null) continue; File jar = m.getJarFile(); // Note: extension JARs not checked. - try { - JarFile j = new JarFile(jar, true); - try { - for (JarEntry entry : NbCollections.iterable(j.entries())) { - String name = entry.getName(); - if (name.endsWith(".class")) { // NOI18N - String clazz = name.substring(0, name.length() - 6).replace('/', '.'); // NOI18N - Throwable t = null; - try { - Class.forName(clazz, false, m.getClassLoader()); - } catch (ClassNotFoundException cnfe) { // e.g. "Will not load classes from default package" from ProxyClassLoader - t = cnfe; - } catch (LinkageError le) { - t = le; - } catch (RuntimeException re) { // e.g. IllegalArgumentException from package defs - t = re; - } - if (t != null) { - // XXX #106153: consider excluding mobility/ant-ext classes - Util.err.log(Level.WARNING, "From " + clazz + " in " + m.getCodeNameBase() + " with effective classpath " + getEffectiveClasspath(m), t); - } + try (JarFile j = new JarFile(jar, true)) { + for (JarEntry entry : NbCollections.iterable(j.entries())) { + String name = entry.getName(); + if (name.endsWith(".class")) { // NOI18N + String clazz = name.substring(0, name.length() - 6).replace('/', '.'); // NOI18N + Throwable t = null; + try { + Class.forName(clazz, false, m.getClassLoader()); + } catch (ClassNotFoundException cnfe) { // e.g. "Will not load classes from default package" from ProxyClassLoader + t = cnfe; + } catch (LinkageError le) { + t = le; + } catch (RuntimeException re) { // e.g. IllegalArgumentException from package defs + t = re; + } + if (t != null) { + // XXX #106153: consider excluding mobility/ant-ext classes + Util.err.log(Level.WARNING, "From " + clazz + " in " + m.getCodeNameBase() + " with effective classpath " + getEffectiveClasspath(m), t); } } - } finally { - j.close(); } } catch (IOException ioe) { Util.err.log(Level.WARNING, null, ioe); @@ -1195,26 +1167,25 @@ final boolean isShowInAutoUpdateClient(ModuleInfo m) { } // OSGi bundles should be considered invisible by default since they are typically autoloads. // (NB modules get AutoUpdate-Show-In-Client inserted into the JAR by the build process.) - if (m instanceof Module) { - return !((Module)m).isNetigso(); + if (m instanceof Module mod) { + return !mod.isNetigso(); } return true; } /** Cache important attributes from module manifests */ - static class Cache implements Stamps.Updater { + static class ManifestCache implements Stamps.Updater { private static final String CACHE = "all-installer.dat"; // NOI18N private final boolean modulePropertiesCached; private final Properties moduleProperties; - public Cache() { + public ManifestCache() { InputStream is = Stamps.getModulesJARs().asStream(CACHE); IF: if (is != null) { Properties p = new Properties(); - try { + try (is) { p.load(is); - is.close(); } catch (IOException ex) { LOG.log(Level.INFO, "Can't load all-installer.dat", ex); break IF; diff --git a/platform/core.startup/test/unit/src/org/netbeans/core/startup/NbInstallerCacheTest.java b/platform/core.startup/test/unit/src/org/netbeans/core/startup/NbInstallerCacheTest.java index 9e071f913eef..446d40dd7fc1 100644 --- a/platform/core.startup/test/unit/src/org/netbeans/core/startup/NbInstallerCacheTest.java +++ b/platform/core.startup/test/unit/src/org/netbeans/core/startup/NbInstallerCacheTest.java @@ -54,7 +54,7 @@ public void testValuesCachedAndEmpty() throws Exception { ModuleManager mm = new ModuleManager(mmi, me); MockModule m = new MockModule(mm, me); - NbInstaller.Cache c = new NbInstaller.Cache(); + NbInstaller.ManifestCache c = new NbInstaller.ManifestCache(); assertEquals("1", c.findProperty(m, "one", true)); assertEquals("One call to module", 1, m.cnt); assertNull(c.findProperty(m, "null", true)); @@ -65,7 +65,7 @@ public void testValuesCachedAndEmpty() throws Exception { m.cnt = 0; StampsTest.reset(); - NbInstaller.Cache loaded = new NbInstaller.Cache(); + NbInstaller.ManifestCache loaded = new NbInstaller.ManifestCache(); assertEquals("1", loaded.findProperty(m, "one", true)); assertEquals("No call to module", 0, m.cnt); assertNull(loaded.findProperty(m, "null", true)); From f6c1df1d01eb07c8c24e10cefa5e5794b0ac75be Mon Sep 17 00:00:00 2001 From: Michael Bien Date: Sun, 29 Mar 2026 09:14:38 +0200 Subject: [PATCH 3/3] Startup logger info dump optimization - remove reflective JDK module info query code - print standard ISO date/time to avoid date formatter bootstrap misc: - removed a test cases testing ThreadDeath as part of the cleanup --- .../org/netbeans/core/startup/TopLogging.java | 86 ++++++------------- .../netbeans/core/startup/TopLoggingTest.java | 20 +---- 2 files changed, 26 insertions(+), 80 deletions(-) diff --git a/platform/core.startup/src/org/netbeans/core/startup/TopLogging.java b/platform/core.startup/src/org/netbeans/core/startup/TopLogging.java index 60cd583ebab8..1a8f1d51f37f 100644 --- a/platform/core.startup/src/org/netbeans/core/startup/TopLogging.java +++ b/platform/core.startup/src/org/netbeans/core/startup/TopLogging.java @@ -25,26 +25,21 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; -import java.io.FileReader; import java.io.IOException; import java.io.PrintStream; import java.io.PrintWriter; -import java.io.Reader; -import java.io.UnsupportedEncodingException; import java.lang.Thread.UncaughtExceptionHandler; -import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; -import java.text.DateFormat; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.time.Instant; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; -import java.util.Date; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Properties; -import java.util.Set; import java.util.StringTokenizer; import java.util.logging.Handler; import java.util.logging.Level; @@ -54,7 +49,6 @@ import java.util.logging.StreamHandler; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; import org.netbeans.NbExit; import org.netbeans.core.startup.logging.NbLogging; import org.openide.filesystems.FileUtil; @@ -181,12 +175,8 @@ private static void initialize(boolean verbose) { try (PrintStream ps = new PrintStream(os)) { logging.printSystemInfo(ps); } - try { - Logger logger = Logger.getLogger(TopLogging.class.getName()); // NOI18N - logger.log(Level.INFO, os.toString("utf-8")); - } catch (UnsupportedEncodingException ex) { - assert false; - } + Logger logger = Logger.getLogger(TopLogging.class.getName()); // NOI18N + logger.log(Level.INFO, os.toString(StandardCharsets.UTF_8)); } if (!Boolean.getBoolean("netbeans.logger.noSystem")) { if (!PrintStreamLogger.isLogger(System.err)) { @@ -202,11 +192,9 @@ private static void initialize(boolean verbose) { private void printSystemInfo(PrintStream ps) { - DateFormat df = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, Locale.US); - Date date = new Date(); ps.println("-------------------------------------------------------------------------------"); // NOI18N - ps.println(">Log Session: "+df.format (date)); // NOI18N + ps.println(">Log Session: " + Instant.now()); // NOI18N ps.println(">System Info: "); // NOI18N List clusters = new ArrayList<>(); @@ -228,20 +216,17 @@ private void printSystemInfo(PrintStream ps) { for (File cluster : clusters) { // also print Hg ID if available; more precise File buildInfo = new File(cluster, "build_info"); // NOI18N if (buildInfo.isFile()) { - try { - try (Reader r = new FileReader(buildInfo)) { - BufferedReader b = new BufferedReader(r); - Pattern p = Pattern.compile("Hg ID: ([0-9a-f]{12})"); // NOI18N - for (;;) { - String line = b.readLine(); - if (line == null) { - break; - } - Matcher m = p.matcher(line); - if (m.matches()) { - ps.print(" (#" + m.group(1) + ")"); // NOI18N - break; - } + Pattern p = Pattern.compile("Hg ID: ([0-9a-f]{12})"); // NOI18N + try (BufferedReader br = Files.newBufferedReader(buildInfo.toPath())) { + for (;;) { + String line = br.readLine(); + if (line == null) { + break; + } + Matcher m = p.matcher(line); + if (m.matches()) { + ps.print(" (#" + m.group(1) + ")"); // NOI18N + break; } } } catch (IOException x) { @@ -276,7 +261,8 @@ private void printSystemInfo(PrintStream ps) { ps.println(" Cache Directory = " + Places.getCacheDirectory()); // NOI18N ps.print( " Installation = "); // NOI18N for (File cluster : clusters) { - ps.print(cluster + "\n "); // NOI18N + ps.println(cluster); + ps.print(" ");// NOI18N } ps.println(CLIOptions.getHomeDir()); // platform cluster is separate ps.println(" Boot & Ext. Classpath = " + createBootClassPath()); // NOI18N @@ -286,9 +272,9 @@ private void printSystemInfo(PrintStream ps) { cp = System.getProperty("java.class.path", "unknown"); // NOI18N } else { StringBuilder sb = new StringBuilder("loaded by "); // NOI18N - if (l instanceof URLClassLoader) { + if (l instanceof URLClassLoader urlCL) { sb.append("URLClassLoader"); // NOI18N - for (URL u : ((URLClassLoader)l).getURLs()) { + for (URL u : urlCL.getURLs()) { sb.append(' ').append(u); } } else { @@ -315,29 +301,10 @@ private static String createBootClassPath() { } private List createJavaBootModuleList() { - // TODO JDK 11 equivalent -// return ModuleLayer.boot().modules().stream() -// .map(Module::getName) -// .sorted() -// .collect(Collectors.toList()); - try { - Class ml_class = Class.forName("java.lang.ModuleLayer"); - Method mod_getName = Class.forName("java.lang.Module").getMethod("getName"); - @SuppressWarnings("unchecked") - Set mods = (Set)ml_class.getDeclaredMethod("modules").invoke( - ml_class.getDeclaredMethod("boot").invoke(null) - ); - return mods.stream().map(mod -> { - try { - return (String) mod_getName.invoke(mod); - } catch (ReflectiveOperationException ex) { - return "unknown"; // outer try would fail first - } - }) - .sorted().collect(Collectors.toList()); - } catch (ReflectiveOperationException ex) { - return Collections.emptyList(); - } + return ModuleLayer.boot().modules().stream() + .map(Module::getName) + .sorted() + .toList(); } /** Scans path list for something that can be added to classpath. @@ -501,9 +468,6 @@ public void uncaughtException(Thread t, Throwable e) { if (e.getClass().getName().endsWith(".ExitSecurityException")) { // NOI18N return; } - if (e instanceof ThreadDeath) { - return; - } g.log(Level.SEVERE, null, e); } } // end of AWTHandler diff --git a/platform/core.startup/test/unit/src/org/netbeans/core/startup/TopLoggingTest.java b/platform/core.startup/test/unit/src/org/netbeans/core/startup/TopLoggingTest.java index 415a6640f912..364772eddf7d 100644 --- a/platform/core.startup/test/unit/src/org/netbeans/core/startup/TopLoggingTest.java +++ b/platform/core.startup/test/unit/src/org/netbeans/core/startup/TopLoggingTest.java @@ -29,11 +29,9 @@ import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.LogManager; -import java.util.logging.LogRecord; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.swing.SwingUtilities; import org.netbeans.junit.NbTestCase; import org.openide.util.Exceptions; import org.openide.util.RequestProcessor; @@ -360,11 +358,7 @@ public void testSystemErrPrintLnIsSentToLog() throws Exception { public void testLoggingFromRequestProcessor() throws Exception { Logger.getLogger("org.openide.util.RequestProcessor").setLevel(Level.ALL); - RequestProcessor.getDefault().post(new Runnable() { - public void run() { - - } - }).waitFinished(); + RequestProcessor.getDefault().post(() -> {}).waitFinished(); } @@ -399,16 +393,4 @@ public void testAttachMessage() throws Exception { // #158906 assertTrue(disk, disk.contains("me please")); } - public void testThreadDeath() throws Exception { // #203171 - Thread t = new Thread(new Runnable() { - @Override public void run() { - throw new ThreadDeath(); - } - }); - t.start(); - t.join(); - String disk = readLog(true); - assertFalse(disk, disk.contains("java.lang.ThreadDeath")); - } - }