Android自动化内存分析学习1:fbjni

最近打算抽空学习一下张绍文老师的《Android开发高手课》。
想要理解本地监控APP内存的框架的实现原理。
发现理解起来都没有那么容易,在阅读代码的过程中,发现C++、linux、hook、framework等方面的功底均有所不足,果然一个人要认识自己,就需要跟外界某种东西发生碰撞和摩擦,才能够真正认识自己。
在此打算创作一系列相关的技术博客,记录所学所想。如果你也有跟我一样的需求和想法。可以持续关注我的这个账号。一起突破。
张绍文老师说过:“看再多的文章,不去思考文章所讲的内容和意图也是没用的;思考再多,不去动手真正实践也是没用的。”

“专栏把进阶的各个主题由点到线串联起来,但这背后必然少不了一些基础的、底层的知识进行支撑”。

而我想要把自己缺失的基础、底层的知识补充起来,记录于此。最终能够实现本地内存监控框架。

使用到的开源库介绍

先来了解使用到的jni相关开源库:fbjni

fbjni

JNI官方文档
fbjni 是从 Facebook 开源的一款jni工具类库,主要提供了工具类,ref utils ,Global JniEnv。

为什么使用JNI wrapper?

Why a JNI wrapper?

标准 JNI 非常冗长且容易出错。fbjni 的目标是使其使用简单、健壮和可扩展。

标准版本的jni代码:

// JNI Example with error handling: toString()
std::string jniToString(JNIEnv* env, jobject self) {
  static auto cls = env->FindClass("java/lang/Object");
  assert(cls != nullptr);
  static auto id = env->GetMethodID(cls, "toString", "()Ljava/lang/String;");
  assert(id != nullptr);

  auto jstr = static_cast<jstring>(env->CallObjectMethod(self, toStringId));
  throwIfJavaExceptionRaised(env);

  auto chbuf = env->GetStringUTFChars(jstr, nullptr);
  throwIfJavaExceptionRaised(env);

  auto stdstr = std::string(chbuf);
  env->ReleaseStringUTFChars(jstr, chbuf);

  return stdstr;
}

使用fbjni工具:
在这个例子中

为了可读性,我们跳过了throwIfJavaExceptionRaised()的实现。使用fbjni,我们可以通过稳健的错误处理大大减少代码。

// fbjni Example: toString()
std::string helperToString(alias_ref<jobject> obj) {
  static auto toStringMethod =
    findClass("java/lang/Object")->getMethod<jstring()>("toString");

  return toStringMethod(obj)->toStdString();
}

实际上,toString()通常很有用,因此我们把它封装的很容易使用。

// fbjni Example (alternative): toString()
std::string helperToString(alias_ref<jobject> obj) {
  return obj->toString();
}

这些实现与普通的JNI示例基本上做相同的事情。主要区别在于,所有错误都是通过抛出C++异常来处理的。在普通的JNI代码中,使用了一些断言来简化代码。

JNI is a C API

API中几乎没有语法糖来帮助您管理资源。由于它只是一个API规范,实现会因JVM而异——web上的大多数文章都假设HotSpot而不是Dalvik。文档严重偏向于Java调用单个独立的本地函数的用例(这通常是一个相当容易处理的用例)。然而,我们的代码通常是异步的,需要Java和本地代码之间的回调或其他有状态的交互。

Memory Lifecycle

Java和native代码有单独的内存堆,因此管理双方使用的对象的生命周期需要格外小心。JNI提供了引用的概念,它允许native代码告诉JVM它仍在使用一个对象,并防止该对象被垃圾收集。从Java调用时,native函数的所有参数都会自动转换为native引用,在调用完成时会删除这些引用。要在native端维护状态或启动对Java的调用,您需要自己管理这些引用。引用来自固定大小的池,因此除了泄漏它们所指向的Java对象之外,泄漏或双重释放引用本身就是一个问题。fbjni提供RAII智能参考,极大地简化了这些引用的管理。
相反,C++智能指针只有在C++代码持有它们的情况下才能生存。通过interpret_cast,指向堆内存的指针可以存储在Java对象中,但您需要确保在Java对象未使用时删除C++分配。fbjni的Hybrid类提供了一种方便的方式来封装这种行为。

Exceptions

C++和Java的大多数用法都使用异常。这两个异常框架是不兼容的,因此碰到JNI边界的异常会成为一个问题:C++异常会导致程序中止,而Java异常则需要C风格检查是否存在错误条件。未处理的Java异常将导致下一个JNI调用中止,这可能与最初导致异常的代码完全无关。fbjni为异常提供了一个翻译工具,使它们能够以合理的方式跨边界传递,并提供了将C++函数封装在try/catch块中的helpers。

Java Type Signatures

native函数需要指定它们所对应的Java函数签名的字符串化版本(称为描述符)。这是一个机制;javac可以为您做到这一点。然而,这种操作流是不方便的;例如,您不能按原样使用javah生成的函数原型,因为它们假定是隐式函数注册,这在旧版本的Android上是不可靠的。如果描述符出错(或者在重构过程中忘记更新它),通常会导致很快但很难调试的崩溃。fbjni包括包装器,这些包装器基于C++函数原型为您推导函数签名。

Type Safety

JNI提供了一个单一的基本对象类型的jobject,并对jstring、jclass和jexception进行了标记专门化。fbjni使得扩展它相对容易,这样任何任意Java类都可以在C++中以类型安全的方式处理。

使用文档

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Android内存分析是指通过分析应用程序在运行过程中的内存使用情况,找出内存泄漏、内存溢出等问题,以优化应用程序的性能和稳定性。常用的工具有Android Studio提供的内存分析器和MAT(Memory Analyzer Tool)等。 在进行Android内存分析时,可以采取以下步骤: 1. 监测内存使用:使用Android Studio提供的内存监视工具,观察应用程序在运行过程中的内存使用情况,包括堆内存和非堆内存的使用情况。 2. 寻找内存泄漏:通过观察内存使用情况,查找是否有对象没有被正确释放,从而导致内存泄漏。可以使用内存分析器来分析堆快照,查找对象引用关系,找出不再需要的对象。 3. 优化内存占用:观察哪些对象占用了大量内存,并尝试优化其内存占用。例如,可以考虑使用弱引用或软引用来管理对象,减少不必要的缓存等。 4. 避免内存溢出:注意合理管理大数据集合、避免频繁创建大对象、及时释放不需要的资源等,以避免应用程序因为内存溢出而崩溃。 5. 使用内存分析工具:Android Studio提供了内存分析器,可以帮助开发者分析内存使用情况,找出内存泄漏和优化内存占用。MAT是一款Java堆内存分析工具,也可用于Android内存分析。 通过进行Android内存分析,开发者可以及时发现和解决应用程序的内存问题,提升应用程序的性能和用户体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林树杰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值