Skip to content

Commit

Permalink
fix: reset code strings cache on low memory, code cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
skylot committed May 14, 2022
1 parent 10c5aff commit 3788555
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 33 deletions.
26 changes: 12 additions & 14 deletions jadx-gui/src/main/java/jadx/gui/JadxWrapper.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package jadx.gui;

import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
Expand Down Expand Up @@ -86,24 +85,23 @@ public void close() {

private void initCodeCache(JadxArgs jadxArgs) {
switch (settings.getCodeCacheMode()) {
case MEMORY: {
case MEMORY:
jadxArgs.setCodeCache(new InMemoryCodeCache());
break;
}
case DISK_WITH_CACHE: {
DiskCodeCache diskCache = new DiskCodeCache(decompiler.getRoot(), getCacheDir());
BufferCodeCache buffer = new BufferCodeCache(diskCache);
jadxArgs.setCodeCache(new CodeStringCache(buffer));
case DISK_WITH_CACHE:
jadxArgs.setCodeCache(new CodeStringCache(buildBufferedDiskCache()));
break;
}
case DISK: {
DiskCodeCache diskCache = new DiskCodeCache(decompiler.getRoot(), getCacheDir());
jadxArgs.setCodeCache(new BufferCodeCache(diskCache));
case DISK:
jadxArgs.setCodeCache(buildBufferedDiskCache());
break;
}
}
}

private BufferCodeCache buildBufferedDiskCache() {
DiskCodeCache diskCache = new DiskCodeCache(decompiler.getRoot(), getCacheDir());
return new BufferCodeCache(diskCache);
}

private Path getCacheDir() {
if (project != null && project.getProjectPath() != null) {
Path projectPath = project.getProjectPath();
Expand All @@ -121,8 +119,8 @@ public void closeCodeCache() {
if (codeCache != null) {
try {
codeCache.close();
} catch (IOException e) {
throw new RuntimeException(e);
} catch (Exception e) {
throw new JadxRuntimeException("Error on cache close", e);
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions jadx-gui/src/main/java/jadx/gui/search/SearchSettings.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import java.util.regex.Pattern;

import org.jetbrains.annotations.Nullable;

import jadx.gui.treemodel.JClass;

public class SearchSettings {
Expand All @@ -20,6 +22,7 @@ public SearchSettings(String searchString, boolean ignoreCase, boolean useRegex)
this.ignoreCase = ignoreCase;
}

@Nullable
public String prepare() {
if (useRegex) {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,6 @@ private String getClassCode(JavaClass javaClass, ICodeCache codeCache) {
}
}

private boolean nextClass() {
clsNum++;
pos = 0;
code = null;
return clsNum >= classes.size();
}

@Override
public int progress() {
return clsNum;
Expand Down
19 changes: 10 additions & 9 deletions jadx-gui/src/main/java/jadx/gui/ui/dialog/SearchDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;

Expand Down Expand Up @@ -114,7 +115,7 @@ public enum SearchOptions {

private transient JTextField searchField;

private transient SearchTask searchTask;
private transient @Nullable SearchTask searchTask;
private transient JButton loadAllButton;
private transient JButton loadMoreButton;

Expand Down Expand Up @@ -315,14 +316,13 @@ private synchronized void search(String text) {
if (text.isEmpty() && !options.contains(SearchOptions.COMMENT)) {
return;
}
LOG.debug("search event: {}", text);
LOG.debug("Building search for '{}', options: {}", text, options);
boolean ignoreCase = options.contains(IGNORE_CASE);
boolean useRegex = options.contains(USE_REGEX);
LOG.debug("Building search, ignoreCase: {}, useRegex: {}", ignoreCase, useRegex);
SearchSettings searchSettings = new SearchSettings(text, ignoreCase, useRegex);
String error = searchSettings.prepare();
if (error == null) {
if (searchField.getBackground() == SEARCH_FIELD_ERROR_COLOR) {
if (Objects.equals(searchField.getBackground(), SEARCH_FIELD_ERROR_COLOR)) {
searchField.setBackground(searchFieldDefaultBgColor);
}
} else {
Expand All @@ -343,6 +343,8 @@ private synchronized void search(String text) {
}

private boolean buildSearch(String text, SearchSettings searchSettings) {
Objects.requireNonNull(searchTask);

List<JavaClass> allClasses;
if (options.contains(ACTIVE_TAB)) {
JumpPosition currentPos = mainWindow.getTabbedPane().getCurrentPosition();
Expand Down Expand Up @@ -394,11 +396,10 @@ private boolean buildSearch(String text, SearchSettings searchSettings) {
}

private synchronized void stopSearchTask() {
if (searchTask == null) {
return;
if (searchTask != null) {
searchTask.cancel();
searchTask.waitTask();
}
searchTask.cancel();
searchTask.waitTask();
}

private synchronized void loadMore() {
Expand Down Expand Up @@ -470,7 +471,7 @@ private synchronized void searchComplete() {
updateTableHighlight();
updateTable();

boolean complete = searchTask.isSearchComplete();
boolean complete = searchTask == null || searchTask.isSearchComplete();
loadAllButton.setEnabled(!complete);
loadMoreButton.setEnabled(!complete);
updateProgressLabel(complete);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,52 @@
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.reactivestreams.Subscriber;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.reactivex.disposables.Disposable;
import io.reactivex.processors.PublishProcessor;

import jadx.api.ICodeCache;
import jadx.api.ICodeInfo;
import jadx.api.impl.DelegateCodeCache;
import jadx.gui.utils.UiUtils;

/**
* Keep code strings for faster search
*/
public class CodeStringCache extends DelegateCodeCache {
private static final Logger LOG = LoggerFactory.getLogger(CodeStringCache.class);

private final Map<String, String> codeCache = new ConcurrentHashMap<>();
private final Subscriber<Boolean> subscriber;
private final Disposable disposable;

public CodeStringCache(ICodeCache backCache) {
super(backCache);
// reset cache if free memory is low
// check only on changes (with debounce) to reduce background checks if app not used
PublishProcessor<Boolean> processor = PublishProcessor.create();
subscriber = processor;
disposable = processor.debounce(3, TimeUnit.SECONDS)
.map(v -> UiUtils.isFreeMemoryAvailable())
.filter(v -> !v)
.subscribe(v -> {
LOG.warn("Free memory is low! Reset code strings cache. Cache size {}", codeCache.size());
codeCache.clear();
System.gc();
});
}

@Override
@Nullable
public String getCode(String clsFullName) {
subscriber.onNext(Boolean.TRUE);
String code = codeCache.get(clsFullName);
if (code != null) {
return code;
Expand All @@ -35,9 +60,15 @@ public String getCode(String clsFullName) {
return backCode;
}

@Override
public @NotNull ICodeInfo get(String clsFullName) {
subscriber.onNext(Boolean.TRUE);
return super.get(clsFullName);
}

@Override
public void add(String clsFullName, ICodeInfo codeInfo) {
// TODO: check if free memory is available before add
subscriber.onNext(Boolean.TRUE);
codeCache.put(clsFullName, codeInfo.getCodeStr());
backCache.add(clsFullName, codeInfo);
}
Expand All @@ -50,7 +81,12 @@ public void remove(String clsFullName) {

@Override
public void close() throws IOException {
codeCache.clear();
backCache.close();
try {
backCache.close();
} finally {
codeCache.clear();
subscriber.onComplete();
disposable.dispose();
}
}
}

0 comments on commit 3788555

Please sign in to comment.