标签: java-native-interface

如何将位图缓存到本机内存中

对于我的10,000点,我决定用这个很酷的网站来点缀一些东西:一种在本机内存上缓存位图的机制.

背景

Android设备的每个应用程序的内存量非常有限 - 堆的范围从16MB到128MB,具体取决于各种参数.

如果您通过此限制,则会获得OOM,当您使用位图时,这可能会发生多次.

很多时候,应用程序可能需要克服这些限制,对巨大的位图执行繁重的操作,或者只是存储它们以供以后使用,并且您需要

我想出的是一个简单的java类,它可以使事情变得更容易.

它使用JNI来存储位图数据,并能够在需要时恢复它.

为了支持该类的多个实例,我必须使用我发现的技巧(这里).

重要笔记

  • 数据仍然存储在RAM中,因此如果设备没有足够的RAM,应用程序可能会被杀死.

  • 记得尽快释放记忆.它不仅可以避免内存泄漏,而且还可以避免在您的应用程序到达后台时首先被系统优先处理.

  • 如果您不想忘记释放内存,可以在每次还原位图时释放它,或者使类实现Closable.

  • 作为一种安全措施,我已经使它在finalize()方法中自动释放其本机内存,但不要让它负责这项工作.风险太大了.当这样的事情发生时,我也写了它写入日志.

  • 它的工作方式是将整个数据复制到JNI对象中,为了还原,它从头开始创建位图并将数据放入其中.

  • 正在使用和恢复的位图采用ARGB_8888格式.当然,您可以将其更改为您想要的任何内容,只是不要忘记更改代码...

  • 大位图可能需要一些时间来存储和恢复,因此在后台线程上执行它可能是明智的.

  • 这不是一个完整的OOM解决方案,但它可能有所帮助.例如,您可以将它与您自己的LruCache结合使用,同时避免将堆内存用于缓存本身.

  • 代码仅用于存储和恢复.如果您需要执行某些操作,则需要进行一些研究.openCV可能就是答案,但是如果你想要执行一些基本的东西,你可以自己实现它们(这里是使用JNI旋转大图像的例子).如果你知道其他选择,请在这里告诉我.

希望这对某些人有用.请写下你的意见.

此外,如果您发现代码有任何问题或建议填补,请告知我们.


好的解决方案

如果您希望在JNI端执行更多操作,您可以使用我所做的这篇文章.它基于我在这里编写的代码,但允许您进行更多操作,您可以轻松添加更多自己的代码.

java-native-interface android caching native bitmap

38
推荐指数
1
解决办法
2万
查看次数

为什么有些Android手机导致我们的应用程序抛出java.lang.UnsatisfiedLinkError?

我们正在体验java.lang.UnsatisfiedLinkError一些在市场上使用我们的应用程序的Android手机.

问题描述:

static
{
    System.loadLibrary("stlport_shared"); // C++ STL        
    System.loadLibrary("lib2"); 
    System.loadLibrary("lib3"); 
}
Run Code Online (Sandbox Code Playgroud)

System.loadLibrary()使用a 使应用程序崩溃java.lang.UnsatisfiedLinkError. java.lang.UnsatisfiedLinkError: Couldn't load stlport_shared from loader dalvik.system.PathClassLoader[dexPath=/data/app/app_id-2.apk,libraryPath=/data/app-lib/app_id-2]: findLibrary returned null

解决方法

我们开始在所有安装上运行一些自定义诊断程序,以检查/data/data/app_id/lib文件夹中是否已解压缩每个lib .

PackageManager m = context.getPackageManager();
String s = context.getPackageName();
PackageInfo p;
p = m.getPackageInfo(s, 0);
s = p.applicationInfo.dataDir;

File appDir = new File(s);
long freeSpace = appDir.getFreeSpace();

File[] appDirList = appDir.listFiles();
int numberOfLibFiles = 0;
boolean subFilesLarger0 = true;
for (int i = 0; i < appDirList.length; i++) …
Run Code Online (Sandbox Code Playgroud)

java-native-interface android native android-ndk unsatisfiedlinkerror

38
推荐指数
2
解决办法
1万
查看次数

从Java调用Win32 API方法

我需要从Java程序中调用Wininet.dll中的一些方法.

我可以找到很多关于如何调用我用Java创建的新DLL的教程,但是我似乎找不到任何关于如何从Java调用已经存在的DLL的教程.

我知道这涉及JNI,但我究竟如何做到这一点?我需要javah在Wininet.h 上调用吗?我在哪里可以获得Wininet.h的副本?指向现有详细教程的指针就足够了.

java java-native-interface winapi

36
推荐指数
2
解决办法
4万
查看次数

JNI - "无法打开包含文件:'jni_md.h'"

此示例程序旨在调用native用C编写的方法.

Java代码

class HelloWorld {

    private native void print();

    public static void main( String args[] ) {
        new HelloWorld().print();
    }

    static {
        System.loadLibrary("HelloWorld");
    }

}
Run Code Online (Sandbox Code Playgroud)

写完这个后,我编译了程序并生成了一个JNI样式头文件.

生成的头文件是:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <C:\Program Files\Java\jdk1.7.0\include\jni.h>
/* Header for class HelloWorld */

#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     HelloWorld
 * Method:    print
 * Signature: ()V
 */
 JNIEXPORT void JNICALL Java_HelloWorld_print
 (JNIEnv *, jobject); …
Run Code Online (Sandbox Code Playgroud)

c java java-native-interface compiler-errors

36
推荐指数
1
解决办法
3万
查看次数

保持对JNIEnv环境的全局引用

JNIEnv在全局存储,所以我稍后可以调用静态java方法.但是存储一个全局指针是否是必要的JNIEnv,它们可以与任何其他java对象一起存储,或者它是一个不需要它的特殊情况.

JNIEnv* globalEnvPointer;

[JNICALL etc] void init(JNIENv* env, [etc])
{
   //required?
   globalEnvPointer = (JNIENv*) (env*)->GetGlobalRef(env, env);
   //or is this OK?
   globalEnvPointer = env;
}
Run Code Online (Sandbox Code Playgroud)

编辑

我在这里有点愚蠢,将使用的所有方法globalEnvPointer都在我的init中调用,因为我init实际上是我的c程序main方法,直到程序结束才会返回.我也在c程序中没有使用其他线程.我认为这简化了答案.

JNIEnv* globalEnvPointer;

[JNICALL etc] void main(JNIENv* env, [etc])
{
   //required?
   globalEnvPointer = (JNIENv*) (env*)->GetGlobalRef(env, env);
   //or is this OK?
   globalEnvPointer = env;
   someMethod();
}

void someMethod()
{
   //use globalEnvPointer here
}
Run Code Online (Sandbox Code Playgroud)

c java-native-interface jnienv

36
推荐指数
1
解决办法
1万
查看次数

是否真的可以避免Java终结器用于本机对等体对象生命周期管理?

根据我作为C++/Java/Android开发人员的经验,我已经了解到终结器几乎总是一个坏主意,唯一的例外是管理Java所需的"本地对等"对象来调用C/C++代码通过JNI.

我知道JNI:正确管理java对象问题的生命周期,但是这个问题解决了不使用终结器的原因,对于本地对等体也是如此.因此,在上述问题中对答案的解释是一个问题/讨论.

Joshua Bloch在他的Effective Java中明确将此案例列为他不使用终结器的着名建议的例外:

终结器的第二个合法使用涉及与本地对等体的对象.本机对等体是普通对象通过本机方法委托的本机对象.由于本机对等体不是普通对象,因此垃圾回收器不知道它,并且在回收Java对等体时无法回收它.假设本地对等方没有关键资源,终结器是执行此任务的适当工具.如果本机对等体拥有必须立即终止的资源,则该类应具有显式终止方法,如上所述.终止方法应该执行释放关键资源所需的任何操作.终止方法可以是本机方法,也可以调用一个.

(另请参阅"堆栈交换中的为什么最终方法包含在Java中?"问题)

然后我看到真正有趣的如何在Google I/O '17中管理Android演讲中的本机内存,其中Hans Boehm实际上主张使用终结器来管理java对象的本地对等,同时引用Effective Java作为参考.在快速提及为什么显式删除本地对等或基于范围的自动关闭可能不是一个可行的替代方案后,他建议使用java.lang.ref.PhantomReference.

他提出了一些有趣的观点,但我并不完全相信.我将尝试通过其中一些并陈述我的疑虑,希望有人能够进一步了解它们.

从这个例子开始:

class BinaryPoly {

    long mNativeHandle; // holds a c++ raw pointer

    private BinaryPoly(long nativeHandle) {
        mNativeHandle = nativeHandle;
    }

    private static native long nativeMultiply(long xCppPtr, long yCppPtr);

    BinaryPoly multiply(BinaryPoly other) {
        return new BinaryPoly ( nativeMultiply(mNativeHandle, other.mNativeHandler) );
    }

    // …

    static native void nativeDelete (long …
Run Code Online (Sandbox Code Playgroud)

java java-native-interface android googleio

36
推荐指数
2
解决办法
1282
查看次数

什么是Java中的本机实现?

如果我们查看Java Object类,那么我们可以找到一些方法,如:

public native int hashCode()
protected native Object clone()
Run Code Online (Sandbox Code Playgroud)

这些本地人是什么?这些方法如何运作?

java java-native-interface

35
推荐指数
4
解决办法
2万
查看次数

将Java应用程序固定到Windows 7任务栏

我使用Launch4j作为我在Windows 7下的Java应用程序的包装器,根据我的理解,本质上它的一个实例javaw.exe依次解释Java代码.因此,在尝试将我的应用程序固定到任务栏时,Windows会反而引脚javaw.exe.如果没有所需的命令行,我的应用程序将无法运行.

将Launch4j应用程序固定到任务栏的结果

如您所见,Windows也没有意识到Java是主机应用程序:应用程序本身被描述为"Java(TM)Platform SE binary".

我尝试更改注册表项HKEY_CLASSES_ROOT\Applications\javaw.exe以添加值IsHostApp.这通过完全禁用我的应用程序的固定来改变行为; 显然不是我想要的.

将javaw.exe指定为宿主应用程序的结果

在阅读了Windows如何解释单个应用程序的实例(以及此问题中讨论的现象)之后,我开始对将应用程序用户模型ID(AppUserModelID)嵌入到我的Java应用程序中感兴趣.

我相信我可以通过传递一个独特AppUserModelID的Windows 来解决这个问题.有一种shell32方法,SetCurrentProcessExplicitAppUserModelID.根据Gregory Pakosz的建议,我实现了它,试图将我的应用程序识别为以下单独的实例javaw.exe:

NativeLibrary lib;
try {
    lib = NativeLibrary.getInstance("shell32");
} catch (Error e) {
    Logger.out.error("Could not load Shell32 library.");
    return;
}
Object[] args = { "Vendor.MyJavaApplication" };
String functionName = "SetCurrentProcessExplicitAppUserModelID";
try {
    Function function = lib.getFunction(functionName);
    int ret = function.invokeInt(args);
    if (ret != 0) {
        Logger.out.error(function.getName() + " returned error …
Run Code Online (Sandbox Code Playgroud)

java java-native-interface taskbar launch4j windows-7

35
推荐指数
2
解决办法
2万
查看次数

为什么我不应该在JNI中重用jclass和/或jmethodID?

这是一个与前一篇文章相关的问题,但这篇文章已经解决,现在我想改变问题的方向.

使用JNI时,有必要询问JNIEnv对象jclass以及jmethodID将在C/C++代码中使用的每个类和方法.为了清楚起见,我想从C/C++调用Java构造函数或方法.

由于从Java到C/C++(反之亦然)的通信成本很高,我最初认为最小化这种方法的一种方法是重用jclassjmethodID.因此,我将此实例保存在全局变量中,如下所示:

jclass    someClass  = NULL;
jmethodID someMethod = NULL;

JNIEXPORT jobject JNICALL Java_example_method1(JNIEnv *env, jobject jobj) {
    // initialize someClass and someMethod if they are NULL
    // use someClass and someMethod to call java (for example, thru NewObject)
}

JNIEXPORT jobject JNICALL Java_example_method2(JNIEnv *env, jobject jobj) {
    // initialize someClass and someMethod if they are NULL
    // use someClass and someMethod to call java again
} …
Run Code Online (Sandbox Code Playgroud)

java java-native-interface

35
推荐指数
3
解决办法
2万
查看次数

35
推荐指数
3
解决办法
2万
查看次数