Use DirectByteBuffer
Seems my mimalloc(I use it as Android's system allocator) doesn't like release memory to system since I replace MADV_DONTNEED with MADV_FREE https://github.com/AcmeUI/android_external_mimalloc but there is no memleak I sure
This commit is contained in:
1 parent
1d8ab51a22
commit
7ac20d59fc
4 files changed
+50
-16
No files matched your search
@@ -250,8 +250,8 @@ Java_com_hippo_UriArchiveAccessor_openArchive(JNIEnv *env, jobject thiz, jint fd
|
||||
return r;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_com_hippo_UriArchiveAccessor_extractToMemfd(JNIEnv *env, jobject thiz, jint index) {
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_com_hippo_UriArchiveAccessor_extractToByteBuffer(JNIEnv *env, jobject thiz, jint index) {
|
||||
EH_UNUSED(env);
|
||||
EH_UNUSED(thiz);
|
||||
archive_ctx *ctx = NULL;
|
||||
@@ -259,13 +259,23 @@ Java_com_hippo_UriArchiveAccessor_extractToMemfd(JNIEnv *env, jobject thiz, jint
|
||||
ret = archive_get_ctx(&ctx, index);
|
||||
if (ret)
|
||||
return 0;
|
||||
int memfd = syscall(SYS_memfd_create, "ArchiveMemFD", 0);
|
||||
ret = archive_read_data_into_fd(ctx->arc, memfd);
|
||||
long long size = archive_entry_size(ctx->entry);
|
||||
void *buffer = malloc(size);
|
||||
if (!buffer) {
|
||||
ctx->using = 0;
|
||||
LOGE("Allocate buffer for decompression failed:ENOMEM");
|
||||
return 0;
|
||||
}
|
||||
ret = archive_read_data(ctx->arc, buffer, size);
|
||||
ctx->using = 0;
|
||||
if (ret == size)
|
||||
return (*env)->NewDirectByteBuffer(env, buffer, size);
|
||||
if (ret != size)
|
||||
LOGE("%s", "No enough data read, WTF?");
|
||||
if (ret < 0)
|
||||
LOGE("%s%s", "Archive read failed:", archive_error_string(ctx->arc));
|
||||
lseek64(memfd, 0, SEEK_SET);
|
||||
return memfd;
|
||||
free(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
@@ -344,4 +354,10 @@ Java_com_hippo_UriArchiveAccessor_extractToFd(JNIEnv *env, jobject thiz, jint in
|
||||
archive_read_data_into_fd(ctx->arc, fd);
|
||||
ctx->using = 0;
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_hippo_UriArchiveAccessor_releaseByteBuffer(JNIEnv *env, jobject thiz, jobject buffer) {
|
||||
void *addr = (*env)->GetDirectBufferAddress(env, buffer);
|
||||
free(addr);
|
||||
}
|
||||
@@ -19,6 +19,7 @@ package com.hippo
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
class UriArchiveAccessor(ctx: Context, uri: Uri) {
|
||||
val pfd by lazy { ctx.contentResolver.openFileDescriptor(uri, "r")!! }
|
||||
@@ -27,7 +28,9 @@ class UriArchiveAccessor(ctx: Context, uri: Uri) {
|
||||
}
|
||||
|
||||
private external fun openArchive(fd: Int, size: Long): Int
|
||||
external fun extractToMemfd(index: Int): Int
|
||||
external fun extractToByteBuffer(index: Int): ByteBuffer
|
||||
|
||||
external fun releaseByteBuffer(buffer: ByteBuffer)
|
||||
external fun extractToFd(index: Int, fd: Int)
|
||||
external fun getFilename(index: Int): String
|
||||
external fun needPassword(): Boolean
|
||||
|
||||
@@ -39,6 +39,7 @@ import com.hippo.yorozuya.thread.PriorityThread;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
@@ -53,7 +54,7 @@ public class ArchiveGalleryProvider extends GalleryProvider2 {
|
||||
public static PVLock pv = new PVLock(0);
|
||||
private final UriArchiveAccessor archiveAccessor;
|
||||
private final Stack<Integer> requests = new Stack<>();
|
||||
private final LinkedHashMap<Integer, Integer> streams = new LinkedHashMap<>();
|
||||
private final LinkedHashMap<Integer, ByteBuffer> streams = new LinkedHashMap<>();
|
||||
private final Thread[] decodeThread = new Thread[]{
|
||||
new Thread(new DecodeTask()),
|
||||
new Thread(new DecodeTask()),
|
||||
@@ -299,10 +300,10 @@ public class ArchiveGalleryProvider extends GalleryProvider2 {
|
||||
}
|
||||
}
|
||||
|
||||
int fd = archiveAccessor.extractToMemfd(index);
|
||||
ByteBuffer buffer = archiveAccessor.extractToByteBuffer(index);
|
||||
|
||||
synchronized (streams) {
|
||||
streams.put(index, fd);
|
||||
streams.put(index, buffer);
|
||||
streams.notify();
|
||||
}
|
||||
}
|
||||
@@ -314,7 +315,7 @@ public class ArchiveGalleryProvider extends GalleryProvider2 {
|
||||
public void run() {
|
||||
while (!Thread.currentThread().isInterrupted()) {
|
||||
int index;
|
||||
int fd;
|
||||
ByteBuffer buffer;
|
||||
synchronized (streams) {
|
||||
if (streams.isEmpty()) {
|
||||
try {
|
||||
@@ -325,15 +326,18 @@ public class ArchiveGalleryProvider extends GalleryProvider2 {
|
||||
continue;
|
||||
}
|
||||
|
||||
Iterator<Map.Entry<Integer, Integer>> iterator = streams.entrySet().iterator();
|
||||
Map.Entry<Integer, Integer> entry = iterator.next();
|
||||
Iterator<Map.Entry<Integer, ByteBuffer>> iterator = streams.entrySet().iterator();
|
||||
Map.Entry<Integer, ByteBuffer> entry = iterator.next();
|
||||
iterator.remove();
|
||||
index = entry.getKey();
|
||||
fd = entry.getValue();
|
||||
buffer = entry.getValue();
|
||||
}
|
||||
|
||||
Image image;
|
||||
image = Image.decode(new FileInputStream(ParcelFileDescriptor.adoptFd(fd).getFileDescriptor()), false); // we take ownership here since this memfd is anon fd
|
||||
image = Image.decode(buffer, false, () -> {
|
||||
archiveAccessor.releaseByteBuffer(buffer);
|
||||
return null;
|
||||
});
|
||||
if (image != null) {
|
||||
notifyPageSucceed(index, image);
|
||||
} else {
|
||||
|
||||
@@ -30,11 +30,13 @@ import android.graphics.drawable.BitmapDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import androidx.core.graphics.drawable.toDrawable
|
||||
import java.io.FileInputStream
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.channels.FileChannel
|
||||
|
||||
class Image private constructor(
|
||||
source: Source?, drawable: Drawable? = null,
|
||||
val hardware: Boolean = true
|
||||
val hardware: Boolean = true,
|
||||
val release: () -> Unit? = {}
|
||||
) {
|
||||
internal var mObtainedDrawable: Drawable?
|
||||
private var mBitmap: Bitmap? = null
|
||||
@@ -72,6 +74,7 @@ class Image private constructor(
|
||||
mObtainedDrawable = null
|
||||
mBitmap?.recycle()
|
||||
mBitmap = null
|
||||
release()
|
||||
}
|
||||
|
||||
private fun prepareBitmap() {
|
||||
@@ -155,6 +158,14 @@ class Image private constructor(
|
||||
return Image(src, hardware = hardware)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun decode(buffer: ByteBuffer, hardware: Boolean = true, release: () -> Unit? = {}): Image {
|
||||
val src = ImageDecoder.createSource(buffer)
|
||||
return Image(src, hardware = hardware) {
|
||||
release()
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun create(bitmap: Bitmap): Image {
|
||||
return Image(null, bitmap.toDrawable(Resources.getSystem()), false)
|
||||
|
||||
Reference in new issue
Block a user