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:
tarsin committed 2022-11-21 12:11:35 +08:00
1 parent 1d8ab51a22
commit 7ac20d59fc
4 files changed
+50 -16

No files matched your search

+22 -6
View File
@@ -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 {
+12 -1
View File
@@ -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)