【GiraKoo】Java Native Interface(JNI)的空间(引用)管理

Java Native Interface(JNI)的空间(引用)管理

Java是通过垃圾回收机制回收内存,C/C++是通过malloc,free,new,delete手动管理空间。那么在JNI层,同时存在Java和C/C++的空间时,该如何进行空间的管理呢?本文参考Oracle的官方文档,对JNI层中空间的管理进行说明。明确哪些内容需要手动调用Delete,哪些不需要手动调用。

一、全局引用(Global References)

全局引用的生命周期(Lifetime),需要主动通过函数调用进行申请和释放。native函数执行完毕后,该空间可继续使用。

函数原型

// 创建全局引用
jobject NewGlobalRef(JNIEnv *env, jobject obj);  

// 删除全局引用
void DeleteGlobalRef(JNIEnv *env, jobject globalRef);

二、局部引用(Local References)

局部引用的生命周期(Lifetime),与调用的native函数一致。当native函数return时,局部引用将会被自动释放。该局部引用占用的空间是JVM的资源。

由于native函数用于存放局部引用的空间是固定的。如果过度的创建局部引用,不加以控制,可能会出现空间不足,程序抛出Out Of Memory(OOM)异常的问题。如果该局部引用已经使用完毕,应尽量手动调用DeleteLocalRef,提前释放空间,避免OOM。

函数原型

// 创建全局引用
jobject NewLocalRef(JNIEnv *env, jobject obj);  

// 删除全局引用
void DeleteLocalRef(JNIEnv *env, jobject localRef);

// 主动设置可创建的局部引用的数量
jint EnsureLocalCapacity(JNIEnv *env, jint capacity);

// 创建一个局部引用的帧,并指定可创建的局部引用的数量。
jint PushLocalFrame(JNIEnv *env, jint capacity);

// 释放当前局部引用的帧,释放全部本地引用。
// 可以通过参数result,将被PopLocalFrame释放的引用转移到上一层的局部引用帧中
jobject PopLocalFrame(JNIEnv *env, jobject result);

特殊说明

  1. 在JDK/JRE 1.1版本中,提供了DeleteLocalRef函数。
  2. 在JDK/JRE 1.2版本中,提供了EnsureLocalCapacityPushLocalFramePopLocalFrameNewLocalRef函数,支持更加复杂的局部引用生命周期能力。

三、弱全局引用(Weak Global Reference)

区别于全局引用(Global References),该引用并不会增加该引用的引用计数。

即持有弱全局引用,不会干预垃圾回收机制(GC)对于该内存的回收。适用于生命周期短的对象,持有生命周期长的引用。

全局引用可以通过jboolean IsSameObject(JNIEnv *env, jobject ref1, jobject ref2); 函数,参数为被判定对象和NULL来判断对象是否存在。如果返回JNI_TRUE判定该弱引用指向的对象是否已经被释放。

使用弱全局引用时,可能会出现执行一半,引用被GC回收的情况。所以需要在使用弱全局引用之前,提供NewLocalRef或者NewGlobalRef,将弱引用转换为强引用。确保GC不会对该空间进行回收。

四、常见问题

1、在native函数中,直接return一个jstring或者其他jobject,是否会有内存泄漏问题?

如果直接return的对象是局部引用(Local Reference),则不会发生内存泄漏问题。
局部引用在native函数执行完毕后,会根据局部引用表(Local Reference Table)进行空间的释放。
当然,手动执行DeleteLocalRef函数进行提前释放,也不会产生问题。

2、什么情况下可能会出现内存泄漏?

1)创建的全局引用(Global Reference),未调用Delete函数进行回收。导致该对象引用计数无法归零。
2)两个对象互相持有对方的强引用。例如A持有B引用,B和C互相持有对方的引用。当A释放B引用时,GC发现C依然持有B的引用,则不会释放B。与此同时,GC也发现B持有C的引用,则不会释放C。导致B和C与其他引用脱离,形成孤岛。这块内存将无法使用,也无法被释放。

3、调用NewString和NewStringUTF时,是否需要释放?

NewStringNewStringUTF函数创建的空间属于局部引用(Local Reference)。可以等待native函数执行完毕后自动回收,也可以在使用完毕(后续不会再访问)后,直接进行Delete释放。

但是需要注意,如果通过GetStringCharsGetStringCritical或者GetStringUTFChars获取了jstring中的char* 空间,则需要使用对应的ReleaseStringCharsReleaseStringCritical或者ReleaseStringUTFChars释放该char* 空间。

参考文章

  • JNI Functions (oracle.com)

Logo
本文来自博客园,作者:GiraKoo
转载请注明原文链接:http://www.cnblogs.com/girakoo/p/17411752.html
友情链接:GiraKoo 博客园 CSDN 稀土掘金

本文转载于网络 如有侵权请联系删除

相关文章

  • python实现微信小游戏“飞机大战”

    以前版本的微信小游戏有一个飞机大战的游戏,学完python之后我试着写了下程序去基本实现这个游戏的部分功能,下面是小游戏飞机大战的python代码注:python中部分代码转自crossin编程教室importpygame importrandom fromsysimportexit#向sys模块借用个exit函数来退出程序 #定义一个敌机类 classEnemy: defrestar(self): #重置敌机位置与速度 self.x=random.randint(100,600) self.y=random.randint(-200,-80) self.speed=random.random()+0.4 def__init__(self): self.restar() self.image=pygame.image.load('enermy.jpg') defmove(self): ifself.y<800: self.y+=self.speed#向下移动 else: self.restar() #定义一个bullet类,封装子弹相关的数据和方法 clas

  • OSI[七层]与TCP/IP[四层]模型简述简图

    OSI参考模型(OSI/RM)的全称是开放系统互连参考模型(OpenSystemIntercon网络OSI参考模型(OSI/RM)的全称是开放系统互连参考模型(OpenSystemInterconnectionReferenceModel,OSI/RM),它是由国际标准化组织(InternationalStandardOrganization,ISO)提出的一个网络系统互连模型。┌─────┐ │应用层   │←第七层 ├─────┤ │ 表示层 │ ├─────┤ │ 会话层 │ ├─────┤ │ 传输层 │ ├─────┤ │ 网络层 │ ├─────┤ │数据链路层│ ├─────┤ │物理层   │←第一层 └─────┘ OSI七层参考模型  在这个OSI七层模型中,每一层都为其上一层提供服务、并为其上一层提供一个访问接口或界面。  不同主机之间的相同层次称为对等层。如主机A中的表示层和主机B中的表示层互为对等层、主机A中的会话层和主机B中的会话层互为对等层等。对等层之间互相通信需要遵守一定的规则,如通信的内容、通信的方式,我们将其称为协议(Protocol)。我们将某个主

  • SpringBoot使用qcloud-vod依赖报错

    日志框架冲突,引入依赖时需要排除掉。<dependency> <groupId>com.qcloud</groupId> <artifactId>vod_api</artifactId> <exclusions> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> </exclusion> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </exclusion> </exclusions> </dependency>复制版权属于:乐心湖'sBlog 本文链接:https://www.xn2001.com/archives/635.h

  • 深入理解Node.js 进程与线程(8000长文彻底搞懂)

    前言进程与线程是一个程序员的必知概念,面试经常被问及,但是一些文章内容只是讲讲理论知识,可能一些小伙伴并没有真的理解,在实际开发中应用也比较少。本篇文章除了介绍概念,通过Node.js的角度讲解进程与线程,并且讲解一些在项目中的实战的应用,让你不仅能迎战面试官还可以在实战中完美应用。文章导览面试会问Node.js是单线程吗? Node.js做耗时的计算时候,如何避免阻塞? Node.js如何实现多进程的开启和关闭? Node.js可以创建线程吗? 你们开发过程中如何实现进程守护的? 除了使用第三方模块,你们自己是否封装过一个多进程架构?进程进程Process是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础,进程是线程的容器(来自百科)。进程是资源分配的最小单位。我们启动一个服务、运行一个实例,就是开一个服务进程,例如Java里的JVM本身就是一个进程,Node.js里通过nodeapp.js开启一个服务进程,多进程就是进程的复制(fork),fork出来的每个进程都拥有自己的独立空间地址、数据栈,一个进程无法访问另外一个进程里定义

  • 2017年自媒体怎么玩?我在WeMedia大会上看到了答案

    12月,WeMedia举办的第三届自媒体年会在京举办。作为早期加入WeMedia联盟的科技自媒体,一直对这个大会保持关注。这几年见证了WeMedia壮大过程,其登陆新三板更是成为自媒体行业的标志性事件,这背后反映的是,自媒体产业的壮大以及自媒体背后的内容产业所发生的翻天覆地的变化。自媒体已成为新媒体生态不可或缺的一部分,发布会、大事件,都有自媒体参与,在一些重大事件中,自媒体甚至扮演了关键角色,自媒体的重要性与日俱增。我注意到,今年WeMedia自媒体大会规模大了很多,出席大会的嘉宾重量级高了不少。还有一个变化是,嘉宾不再是品牌赞助商为主,业内很具代表性的几家内容平台的掌门人都出席演讲,这表明内容创作者被争夺得日益激烈,看来自媒体依然是风口。这些嘉宾分享了不少干货,值得自媒体和内容产业关注。快手亮相,自媒体视频化、下沉化一篇《喊麦之王天佑如何统治直播江湖》让快手这个短视频隐形巨头浮出水面,这类“实力强悍但很低调”的隐形玩家不少,不过,在本身就属于媒体的短视频行业能隐藏自己还是挺沉得住气的。快手CEO宿华几乎不参加公开活动,这一次参加WeMedia年会算是首次亮相,宿华在大会透露,《喊麦

  • SIG蓝牙技术规范分享

    蓝牙技术联盟,BluetoothSpecialInterestGroup,简称:SIG。SIG是一个以制定蓝牙技术规范,推动蓝牙技术发展为宗旨的跨国组织。其拥有蓝牙的商标及认证等, 授权给其他厂商使用蓝牙技术和标志, 但本身不负责具体蓝牙装置的设计、生产等。蓝牙(Bluetooth)技术被广泛应用,至今超过100亿设备;主要应用在各种无线短距应用场景,如智能手机、可穿戴电子设备等。 将我们从有线技术的束缚中解放出来。 蓝牙名称的由来可以追溯到一千多年前,丹麦国王HaraldBlatand统一丹麦的故事。至今为止,蓝牙技术标准从1.1发展到5.x;传输速度、效率、距离,可靠性,安全等指标都在不断优化和提升。其载体是基带芯片,芯片的设计、制造技术也在不断发展,拥有更高主频,FLASH&RAM更大, 单芯片集成更多通信协议:Wi-Fi、蓝牙、Ethernet。 单芯片集成更多硬件单元:CPU、PMU、RAM、FLASH、LNA、PA等。拥有更宽工作电压,集成更多I/O, 以适配蓝牙的新指标和相关功能。 蓝牙工作在2.4GHzISM频段, 频率范围为:2400~2483.5MHz。根

  • 微服务(Microservices)——Martin Flower

    原文是MartinFlower于2014年3月25日写的《Microservices》。 这是一篇枯燥乏味的文章,但它足够能让你更深层次了解微服务。没有梦想,何必远方。加油吧!!!微服务“微服务架构(MicroserviceArchitecture)”一词在过去几年里广泛的传播,它用于描述一种设计应用程序的特别方式,作为一套独立可部署的服务。目前,这种架构方式还没有准确的定义,但是在围绕业务能力的组织、自动部署(automateddeployment)、端智能(intelligenceintheendpoints)、语言和数据的分散控制,却有着某种共同的特征。“微服务(Microservices)”——只不过在满大街充斥的软件架构中的一新名词而已。尽管我们非常鄙视这样的东西,但是这玩意所描述的软件风格,越来越引起我们的注意。在过去几年里,我们发现越来越多的项目开始使用这种风格,以至于我们身边的同事在构建企业级应用时,把它理所当然的认为这是一种默认开发形式。然而,很不幸,微服务风格是什么,应该怎么开发,关于这样的理论描述却很难找到。简而言之,微服务架构风格,就像是把一个单独的应用程序开发

  • 常见漏洞扫描工具_web漏洞扫描工具有哪些

    大家好,又见面了,我是你们的朋友全栈君 漏洞扫描漏洞扫描是指基于漏洞数据库,通过扫描等手段对指定的远程或者本地计算机系统的安全脆弱性进行检测,发现可利用漏洞的一种安全检测(渗透攻击)行为。 漏洞扫描器包括网络漏扫、主机漏扫、数据库漏扫等不同种类。常用漏洞扫描工具:一、Nessus百度百科:Nessus是目前全世界最多人使用的系统漏洞扫描与分析软件。总共有超过75,000个机构使用Nessus作为扫描该机构电脑系统的软件。提供完整的电脑漏洞扫描服务,并随时更新其漏洞数据库。不同于传统的漏洞扫描软件,Nessus可同时在本机或远端上摇控,进行系统的漏洞分析扫描。其运作效能能随着系统的资源而自行调整。如果将主机加入更多的资源(例如加快CPU速度或增加内存大小),其效率表现可因为丰富资源而提高。二、Nmap百度百科:nmap是一个网络连接端扫描软件,用来扫描网上电脑开放的网络连接端。确定哪些服务运行在哪些连接端,并且推断计算机运行哪个操作系统(这是亦称fingerprinting)。它是网络管理员必用的软件之一,以及用以评估网络系统安全。 Nmap支持的扫描方式 ①参数-sP:对目标采用Pin

  • Huntworld伤害世界Windows SteamCMD开服教程

    服务器要求内存:6G以上即可,越高越好,根据期望用户量增加。网络:5M以上的带宽,根据用户量增加,游戏服务器容易被ddos攻击,最好弄高防御的服务器或者配置网络防御能力。端口:TCP12871如果你还没有服务器,可以看看我的服务器活动汇总页面,选择您心仪的活动进行购买~准备工作点击下载SteamCMD点击下载Notepad++安装服务端在桌面创建一个SteamCMD文件夹,将下载的SteamCMD压缩包解压进去启动SteamCMD等待下载安装显示Steam>时代表已经安装完毕输入以下代码登陆下载loginanonymousapp_update405100validate复制等待下载完成后exit配置服务端点击下载Oxide打开SteamCMD\steamapps\common\HurtworldDedicatedServer\将下载的Oxide.Hurtworld.zip文件全部解压到本文件夹启动服务器根目录的host.bat文件初始化服务器会生成一个Compiler.exe的文件(没有生成需要去Oxide官网下载)关闭host.bat,在服务端新建一个autoexec.cfg文

  • ux.form.field.TreePicker 扩展,修复火狐不能展开bug

    1/** 2*APickerfieldthatcontainsatreepanelonitspopup,enablingselectionoftreenodes. 3*动态绑定store,修复火狐点击穿透bug 4*水平有限,可能有新坑 5*/ 6Ext.define('ux.form.field.TreePicker',{ 7extend:'Ext.form.field.Picker', 8xtype:'uxTreepicker', 9mixins:['Ext.util.StoreHolder'], 10uses:['Ext.tree.Panel'], 11triggerCls:Ext.baseCSSPrefix+'form-arrow-trigger', 12 13config:{ 14/** 15*@cfg{Ext.data.TreeStore}store 16*Atreestorethatthetreepickerwillbeboundto 17*/ 18store:null, 19 20/** 21*@cfg{String}displayField 22*Thefieldin

  • Kubernetes HPA

    HPA控制器介绍 当系统资源过高的时候,我们可以使用如下命令来实现Pod的扩缩容功能 $kubectl-nluffyscaledeploymentmyblog--replicas=2 复制 但是这个过程是手动操作的。在实际项目中,我们需要做到是的是一个自动化感知并自动扩容的操作。Kubernetes也为提供了这样的一个资源对象:HorizontalPodAutoscaling(Pod水平自动伸缩),简称HPA 基本原理:HPA通过监控分析控制器控制的所有Pod的负载变化情况来确定是否需要调整Pod的副本数量 HPA的实现有两个版本: autoscaling/v1,只包含了根据CPU指标的检测,稳定版本 autoscaling/v2beta1,支持根据memory或者用户自定义指标进行伸缩 如何获取Pod的监控数据? k8s1.8以下:使用heapster,1.11版本完全废弃 k8s1.8以上:使用metric-server 思考:为什么之前用heapster,现在废弃了项目,改用metric-server? heapster时代,apiserver会直接将metric请求通

  • 计算方法2 插值与函数逼近

    心态崩了,这个latex公式支持也太迷幻了。但是不太想管,等啥时候有空整个自己的吧(flag++) 函数逼近 考虑的是对于给定函数\(f\)和度量\(\norm{\cdot}\),求一个多项式函数\(p\)使得\(\norm{f-p}\)尽可能小。这里不关注特定点上的值,而更在意两个函数总体的距离。 Weierstrass逼近定理 若\(f\inC[a,b]\),那么存在多项式列\(\left\{F_n\right\}\),使得\(\norm{\lim\limits_{n\rightarrow\infty}F_n-f}_{\infty}=0\) \(\norm{f}_{\infty}\)的含义是\(\supR(f)\),即值域的上确界。 注意到\([a,b]\)是任意的。为了便于讨论,一般通过伸缩平移到\([-1,1]\)上考虑。 Bernstein(又是他)给了一个构造性的证明,他构造出的多项式即为大名鼎鼎的Bernstein多项式。证明的技巧比较强,这里就不放了,感觉再抄一遍也没啥用.... Chebyshev多项式 特殊的多项式族,规定了\(n\)次多项式一致逼近的误差下界。 定

  • [原创]VM虚拟机Centos6.4网络配置。

    关于虚拟机VMware3种网络模式(桥接、nat、Host-only)的工作原理http://www.cnblogs.com/hehexiaoxia/p/4042583.html 操作环境 主机:WindowsServer2008 虚拟机:VMwarestation9 虚拟机里的系统:Centos6.4 一、桥接配置   在桥接模式下,VMware虚拟出来的操作系统就像是局域网中的一独立的主机,它可以访问网内任何一台机器不过你需要多于一个的IP地址,并且需要手工为虚拟系统配置IP地址子网掩码,而且还要和宿主机器处于同一网段,这样虚拟系统才能和宿主机器进行通信。如果你想利用VMware在局域网内新建一个虚拟服务器,为局域网用户提供网络服务,就应该选择桥接模式。 1、打开VMwareWorkstation菜单Edit,点击VirtualNetworkEditor...,选择VMnet0,VMnetInformation中Bridgedto选择第二项,OK! 2、重启虚拟机,进入终端,输入ifconfigeth0,查看一下eth0的网络设置。 3、设置固定网络,首先进入root

  • Groundhog Build Home - HDU - 3932(模拟退火)

    题意 给定一个矩形内的\(n\)个点,在矩形中找一个点,离其他点的最大距离最小。 题解 模拟退火。 这个题需要\(x\)和\(y\)坐标随机动的时候多随机几次。否则就WA了。另外由于随机多次,如果温度变化率太小,就会TLE。 代码 //#include<bits/stdc++.h> #include<cstdio> #include<cmath> #include<ctime> #include<algorithm> #include<iostream> #defineFOPIfreopen("in.txt","r",stdin) #defineFOPOfreopen("out.txt","w",stdout) usingnamespacestd; typedeflonglongLL; constintmaxn=1000+5; constdoubleeps=1e-8; constintinf=0x3f3f3f3f; constdoublestart_T=20000; structPoint { doublex

  • iOS判断是否是手写键盘

    github: 思路:遍历键盘window的subviews,如果发现UIKBHandwritingView,则当前键盘为手写键盘; 手写键盘的位置: p.p1{margin:0;font:11pxMenlo;color:rgba(0,0,0,1)} span.s1{font-variant-ligatures:no-common-ligatures} UIRemoteKeyboardWindow  p.p1{margin:0;font:11pxMenlo;color:rgba(0,0,0,1)} span.s1{font-variant-ligatures:no-common-ligatures}   UIInputSetContainerView p.p1{margin:0;font:11pxMenlo;color:rgba(0,0,0,1)} span.s1{font-variant-ligatures:no-common-ligatures}     UIInputSetHostView p.p1{margin:0;font:11pxMenlo;color:rgba(

  • Qt实现应用程序单实例运行--LocalServer方式

    使Qt应用程序能够单实例运行的典型实现方法是使用共享内存实现。该方法实现简单,代码简洁。 但有一个致命缺陷:共享内存(QSharedMemory)实现的单程序运行,当运行环境是UNIX时,并且程序不幸崩溃,会导致共享内存无法释放,从而无法重新运行程序!   所以应该寻找其他的使Qt应用程序能够单实例运行的方案。于是找到LocalSocket和LocalServer通讯方案(据说Qt官方商业版的QSingleApplication的原理好像跟这个差不多)。 “要用到Qt的QLocalSocket,QLocalServer类,这两个类从接口上看和网络通信socket没有区别,但是它并不是真正的网络API,只是模仿了而已。这两个类在Unix/Linux系统上采用Unix域socket实现,而在Windows上则采用有名管道(namedpipe)来实现。” 参见: http://www.oschina.net/code/snippet_54100_629 http://blog.csdn.net/qq19831030qq/article/details/6199896  

  • 在广播中弹出AlertDialog

    1,<uses-permissionandroid:name="android.permission.SYSTEM_ALERT_WINDOW"/> 2,alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 复制

  • Entity Framework Code First 常用方法集成

    usingSystem; usingSystem.Collections.Generic; usingSystem.Data.Entity; usingSystem.Linq; usingSystem.Linq.Expressions; usingSystem.Text; usingSnsDB; usingEntityFramework.Extensions; usingEntityFramework.Reflection; usingSystem.Data.SqlClient; usingSystem.Transactions; namespaceSnsDAL { publicpartialclassRepository { ///<summary> ///创建一条记录 ///</summary> ///<typeparamname="T"></typeparam> ///<paramname="model"></param> ///<returns></returns> publici

  • Fiddler工具使用介绍一

    Fiddler基础知识 Fiddler是强大的抓包工具,它的原理是以web代理服务器的形式进行工作的,使用的代理地址是:127.0.0.1,端口默认为8888,我们也可以通过设置进行修改。 代理就是在客户端和服务器之间设置一道关卡,客户端先将请求数据发送出去后,代理服务器会将数据包进行拦截,代理服务器再冒充客户端发送数据到服务器;同理,服务器将响应数据返回,代理服务器也会将数据拦截,再返回给客户端。 Fiddler可以抓取支持http代理的任意程序的数据包,如果要抓取https会话,要先安装证书。 HTTP协议 要分析Fiddler抓取的数据包,我们首先要熟悉HTTP协议。HTTP即超文本传输协议,是一个基于请求与响应模式的、无状态的、应用层的协议,绝大多数的Web开发,都是构建在HTTP协议之上的Web应用。 HTTP的工作过程:当我们请求一个超链接时,HTTP就开始工作了,客户端先发送一个请求到服务器,请求内容包括:协议版本号、请求地址、请求方式、请求头和请求参数;服务器收到请求后做相应的处理,并将响应数据返回到客户端,响应内容包括:协议版本号、状态码和响应数据。前端根据响应

  • linux-gcc基础篇

    预编译编译汇编链接 动态库链接   静态库连接   参考链接: https://www.cnblogs.com/ggjucheng/archive/2011/12/14/2287738.html#_Toc311642846

  • python的访问限制(下划线的用法)

    python通过在属性或者方法名前面加 单下划线,双下划线,首尾双下划线 来限制访问权限。 1.首尾双下划线:定义特殊方法,一般是系统名,如__init__() 2.单下划线:表示保护protected类型的成员,允许类本身和子类访问,但不能用frommoduleimport*来导入;保护属性可以通过实例名访问。 3.双下划线:表示私有private类型的成员,只允许类本身访问,不能通过实例+属性访问,但可以在实例方法中访问,也可以通过实例名._类名__属性访问。

相关推荐

推荐阅读