Skip to content

Commit

Permalink
Avoid storing the whole BuildResult in StartupActionImpl
Browse files Browse the repository at this point in the history
The BuildResult contains references to all the build items, some of them
contain references to class loaders or objects of significant size.
  • Loading branch information
gsmet authored and yrodiere committed Aug 17, 2023
1 parent 595a40f commit 708ea79
Showing 1 changed file with 29 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
Expand Down Expand Up @@ -45,27 +45,36 @@ public class StartupActionImpl implements StartupAction {
private static final Logger log = Logger.getLogger(StartupActionImpl.class);

private final CuratedApplication curatedApplication;
private final BuildResult buildResult;
private final QuarkusClassLoader runtimeClassLoader;

private final String mainClassName;
private final String applicationClassName;
private final Map<String, String> devServicesProperties;
private final List<RuntimeApplicationShutdownBuildItem> runtimeApplicationShutdownBuildItems;

public StartupActionImpl(CuratedApplication curatedApplication, BuildResult buildResult) {
this.curatedApplication = curatedApplication;
this.buildResult = buildResult;

this.mainClassName = buildResult.consume(MainClassBuildItem.class).getClassName();
this.applicationClassName = buildResult.consume(ApplicationClassNameBuildItem.class).getClassName();
this.devServicesProperties = extractDevServicesProperties(buildResult);
this.runtimeApplicationShutdownBuildItems = buildResult.consumeMulti(RuntimeApplicationShutdownBuildItem.class);

Set<String> eagerClasses = new HashSet<>();
Map<String, byte[]> transformedClasses = extractTransformers(eagerClasses);
Map<String, byte[]> transformedClasses = extractTransformers(buildResult, eagerClasses);
QuarkusClassLoader baseClassLoader = curatedApplication.getBaseRuntimeClassLoader();
QuarkusClassLoader runtimeClassLoader;

//so we have some differences between dev and test mode here.
//test mode only has a single class loader, while dev uses a disposable runtime class loader
//that is discarded between restarts
Map<String, byte[]> resources = new HashMap<>(extractGeneratedResources(true));
Map<String, byte[]> resources = new HashMap<>(extractGeneratedResources(buildResult, true));
if (curatedApplication.isFlatClassPath()) {
resources.putAll(extractGeneratedResources(false));
resources.putAll(extractGeneratedResources(buildResult, false));
baseClassLoader.reset(resources, transformedClasses);
runtimeClassLoader = baseClassLoader;
} else {
baseClassLoader.reset(extractGeneratedResources(false),
baseClassLoader.reset(extractGeneratedResources(buildResult, false),
transformedClasses);
runtimeClassLoader = curatedApplication.createRuntimeClassLoader(
resources, transformedClasses);
Expand All @@ -91,7 +100,7 @@ public RunningQuarkusApplication runMainClass(String... args) throws Exception {
//we have our class loaders
ClassLoader old = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(runtimeClassLoader);
final String className = buildResult.consume(MainClassBuildItem.class).getClassName();
final String className = mainClassName;
try {
// force init here
Class<?> appClass = Class.forName(className, true, runtimeClassLoader);
Expand All @@ -109,7 +118,7 @@ public void run() {
ApplicationStateNotification.notifyStartupFailed(e);
}
} finally {
for (var i : buildResult.consumeMulti(RuntimeApplicationShutdownBuildItem.class)) {
for (var i : runtimeApplicationShutdownBuildItems) {
try {
i.getCloseTask().run();
} catch (Throwable t) {
Expand Down Expand Up @@ -180,7 +189,7 @@ public int runMainClassBlocking(String... args) throws Exception {
//we have our class loaders
ClassLoader old = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(runtimeClassLoader);
final String className = buildResult.consume(MainClassBuildItem.class).getClassName();
final String className = mainClassName;
try {
AtomicInteger result = new AtomicInteger();
Class<?> lifecycleManager = Class.forName(ApplicationLifecycleManager.class.getName(), true, runtimeClassLoader);
Expand Down Expand Up @@ -224,7 +233,7 @@ public void run() {
} finally {
runtimeClassLoader.close();
Thread.currentThread().setContextClassLoader(old);
for (var i : buildResult.consumeMulti(RuntimeApplicationShutdownBuildItem.class)) {
for (var i : runtimeApplicationShutdownBuildItems) {
try {
i.getCloseTask().run();
} catch (Throwable t) {
Expand All @@ -250,7 +259,7 @@ public RunningQuarkusApplication run(String... args) throws Exception {
ClassLoader old = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(runtimeClassLoader);
final String className = buildResult.consume(ApplicationClassNameBuildItem.class).getClassName();
final String className = applicationClassName;
Class<?> appClass;
try {
// force init here
Expand Down Expand Up @@ -289,7 +298,7 @@ public void close() throws IOException {
} finally {
ForkJoinClassLoading.setForkJoinClassLoader(ClassLoader.getSystemClassLoader());

for (var i : buildResult.consumeMulti(RuntimeApplicationShutdownBuildItem.class)) {
for (var i : runtimeApplicationShutdownBuildItems) {
try {
i.getCloseTask().run();
} catch (Throwable t) {
Expand Down Expand Up @@ -323,15 +332,19 @@ public ClassLoader getClassLoader() {

@Override
public Map<String, String> getDevServicesProperties() {
return devServicesProperties;
}

private static Map<String, String> extractDevServicesProperties(BuildResult buildResult) {
DevServicesLauncherConfigResultBuildItem result = buildResult
.consumeOptional(DevServicesLauncherConfigResultBuildItem.class);
if (result == null) {
return Collections.emptyMap();
return Map.of();
}
return new HashMap<>(result.getConfig());
}

private Map<String, byte[]> extractTransformers(Set<String> eagerClasses) {
private static Map<String, byte[]> extractTransformers(BuildResult buildResult, Set<String> eagerClasses) {
Map<String, byte[]> ret = new HashMap<>();
TransformedClassesBuildItem transformers = buildResult.consume(TransformedClassesBuildItem.class);
for (Set<TransformedClassesBuildItem.TransformedClass> i : transformers.getTransformedClassesByJar().values()) {
Expand All @@ -347,7 +360,7 @@ private Map<String, byte[]> extractTransformers(Set<String> eagerClasses) {
return ret;
}

private Map<String, byte[]> extractGeneratedResources(boolean applicationClasses) {
private static Map<String, byte[]> extractGeneratedResources(BuildResult buildResult, boolean applicationClasses) {
Map<String, byte[]> data = new HashMap<>();
for (GeneratedClassBuildItem i : buildResult.consumeMulti(GeneratedClassBuildItem.class)) {
if (i.isApplicationClass() == applicationClasses) {
Expand Down

0 comments on commit 708ea79

Please sign in to comment.