首页 文章 精选 留言 我的

精选列表

搜索[网站开发],共10000篇文章
优秀的个人博客,低调大师

Android NDK开发系列教程5:局部引用,全局引用,弱全局引用

终于建了一个自己个人小站:https://huangtianyu.gitee.io,以后优先更新小站博客,欢迎进站,O(∩_∩)O~~ 1. 简介 从Java虚拟机创建的对象当传入到native层时会产生一个引用,在进行垃圾回收时如果有native的引用,改对象同样也不会被回收。在native引用中分局部引用和全局引用。 1.1 局部引用 局部引用又称本地引用,大多数见到的引用都是局部引用,例如通过NewLocalRef和各种JNI接口创建(FindClass、NewObject、GetObjectClass和NewCharArray等),局部引用只会在本次native调用中有效,当本次调用结束后该引用即被自动释放。局部引用会阻止GC进行回收。同时也可以调用DeleteLocalRef函数来手动释放(比如在循环里面用到了局部引用而退出循环没有使用该局部引用,那么就需要在循环中释放该局部引用)。通常使用NewObject创建的实例返回的也是局部引用。千万不要把局部引用保存为c++的全局变量或者把它定义为静态变量,局部引用的有效期是一次Java本地调用。 JNI提供了一系列函数来管理局部引用的生命周期。这些函数包括:EnsureLocalCapacity、NewLocalRef、PushLocalFrame、PopLocalFrame、DeleteLocalRef。 //申请扩充局部引用的最大个数限制,返回值等于0的时候表示成功,>0时表示内存溢出。默认至少16个局部引用可以使用,引用数超出时报FatalError jint (*EnsureLocalCapacity)(JNIEnv*, jint); /* PushLocalFrame是一个创建本地引用新作用域的有用函数,这使得PushLocalFrame函数可以释放其使用的框架中所有已分配的本地引用。当该函数被调用时,本地引用的最低数量将在本框架中被创建。该函数如果执行成功则返回0,如果由于错误抛出一个OutOfMemoryException,则返回一个负值。*/ jint PushLocalFrame(jint capacity); /*PopLocalFrame函数释放当前框架中的所有本地引用(弹出一个框架)。因为存储该函数的结果(返回值)可能会导致在即将被弹出的框架中创建一个本地引用,该函数接收一个可以导致引用在当前框架被弹出之后的最高框架中创建的参数。这就确保可以维护一个存储PopLocalFrame函数结果的引用。*/ jobject PopLocalFrame(jobject result); PushLocalFrame为当前函数中局部引用创建了一个引用堆栈,在每遍历一次调用(*env)->GetObjectArrayElement(env, arr, i);返回一个局部引用时,JVM会自动将该引用压入当前局部引用栈中。而PopLocalFrame负责将栈中所有引用释放。这样一来,Push/PopLocalFrame函数对提供了对局部引用生命周期更方便的管理,不用再去一个个Delete了。 1.2 全局引用 全局引用可以在当前线程使用,也可以在其他线程使用,可以保存在本地的static静态变量或全局变量中,全局引用需要调用NewGlobalRel函数创建,释放时采用ReleaseGlobalRef函数释放。有效作用域在创建后,一直到调用ReleaseGlobalRef释放时。 1.3 弱全局引用 在Java1.2中,新增了弱全局引用,与全局变量一样其创建、删除均需要编程写出,也可以在本地多个代码中使用,也可以跨进程使用。不一样的是,它的存在不影响垃圾回收机制对该引用所指向对象实例的回收。其创建采用NewWeakGlobalRef,释放采用ReleaseWeakGlobalRel。 以上涉及的函数主要有以下几个: //创建局部引用 jobject NewLocalRef(jobject obj); //释放局部引用 void DeleteLocalRef(jobject obj); //创建全局引用 jobject NewGlobalRef(jobject obj); //释放全局引用 void DeleteGobalRef(jobject obj); //创建弱全局引用 jobject NewWeakGlobalRef(jobject obj); //释放弱全局引用 void DeleteWeakGlobalRef(jobject obj); //该方法判断两个引用是否相等,对于弱全局引用如果对比的是NULL那么还可以判断该引用指向的对象是否被回收 jboolean IsSameObject(jobject obj1 , jobject obj2); 上述三中引用会影响内存的回收,在C/C++中没有向Java一样的垃圾回收机制,自己申请的内存要记得自己去释放了,否则会导致内存泄漏。虽然现在C/C++里面也有智能指针,但相对而言这个智能指针用起来不如Java。所以在C的世界里要遵循谁申请,谁释放的基本原则。 2. 举个栗子 上面介绍了基本知识,下面给出相应的例子来进行说明下。 2.1局部引用 //1. 局部引用不要存储在static变量中,即使存了下次也不能用 //static jclass cls; //以下创建的局部引用都放入到栈中 env->PushLocalFrame(16); jclass cls; if (!cls) {//这里就错误了,前一次方法完成后jvm会释放局部引用,这里static存的值仅第一次有效 cls = env->GetObjectClass(instance);//这里的cls是局部引用 } //删除栈里面的局部引用 env->PopLocalFrame(NULL); env->EnsureLocalCapacity(20);//将本地引用的最大限制改为20 //下面可以进行其他操作。。。 在局部引用中要注意以下几方面: 1. 循环体内创建的局部引用,要在循环体内就直接释放了。 2. 编写的工具函数,里面创建的局部引用,要在该工具函数里面释放了。 3. 局部引用引用了一个大的Java对象,这时候一定一定要早点释放了。 4. 局部引用不要缓存在native层 2.2 全局引用 extern "C" JNIEXPORT void JNICALL Java_zqc_com_example_NativeTest_jniGlobalRef(JNIEnv *env, jobject instance) { static jobject obj; static jclass pCls; if (obj) {//第二次点击时,这里就不会空 //由于obj和personCls被保存为全局引用了,所有这里使用仍然有效 jmethodID getId = env->GetMethodID(pCls, "getName", "()Ljava/lang/String;"); jstring name = (jstring) env->CallObjectMethod(obj, getId); LOGE("obj is not null, name:%s", jstringToChar(env, name)); return; } if (!pCls) {//为空就去新建 jclass tmpCls = env->FindClass("zqc/com/example/Person"); pCls = (jclass) env->NewGlobalRef(tmpCls); env->DeleteLocalRef(tmpCls); } jmethodID conMid = env->GetMethodID(pCls, "<init>", "()V"); jobject tmpObj = env->NewObject(pCls, conMid); jmethodID setId = env->GetMethodID(pCls, "setName", "(Ljava/lang/String;)V"); env->CallVoidMethod(tmpObj, setId, env->NewStringUTF("看看姓名")); obj = env->NewGlobalRef(tmpObj); env->DeleteLocalRef(tmpObj); } 2.3 弱全局引用 弱全局引用和全局引用基本差不多,最大的区别就是弱全局引用不影响GC的回收。在使用弱全局引用的时候一定要注意,使用前要检查下是不是被GC回收了。 extern "C" JNIEXPORT void JNICALL Java_zqc_com_example_NativeTest_jniWeakGlobalRef(JNIEnv *env, jobject instance) { static jclass pCls; if (!pCls) { jclass tmpCls = env->FindClass("zqc/com/example/Person"); pCls = (jclass) env->NewWeakGlobalRef(tmpCls); env->DeleteLocalRef(tmpCls); } //除了第一次需要FindClass外,在没有回收pCls之前都可以使用 //这里使用... //可以手动释放 //env->DeleteWeakGlobalRef(pCls); } 3. 引用的比较 jni提供了相应的函数 jboolean IsSameObject(jobject ref1, jobject ref2) { return functions->IsSameObject(this, ref1, ref2); } 如果两个引用指向同一个实例则返回JNI_TRUE,否则返回JNI_FALSE。

优秀的个人博客,低调大师

Centos搭建开发环境,PHP7+ Nginx1.12+ Mysql5.7

1.更新yum源 yum -yupdate 2.安装 epel-release yum install epel-release-y 检测安装成功:yum search nginx 结果含有:nginx.x86_64 : A high performance webserver andreverse proxyserver 表示成功 CentOS 系列的服务器系统有一个毛病,就是官方自带的源的软件比较古老,并且很多的软件都没有。因为他们的首要任务是保证服务器的稳定,而不是追求最新。但是太过于保守了,一般来说,我们会给服务器添加一个 epel-release 这个源。这个源里包含了例如 nginx 之类的我们需要的软件,使用起来比较方便。 3.安装服务器常用软件 yum -y install vim* Vim是一个类似于Vi的著名的功能强大、高度可定制的文本编辑器 yum install wget wget 是一个从网络上自动下载文件的自由工具,支持通过 HTTP、HTTPS、FTP 三个最常见的 TCP/IP协议 下载,并可以使用 HTTP 代理。 yum -y install lrzsz lrzsz是一款在linux里可代替ftp上传和下载的程序。 yum install zip unzip 作用:zip压缩、unzip解压缩 4.安装Nginx nginx 依赖的一些 lib 库: yum install gcc-c++ yum install pcre pcre-devel yum install zlib zlib-devel yum install openssl openssl--devel 安装 Nginx cd /usr/local 打开 usr 下的 local 文件夹 yum install nginx -y 安装Nginx,此安装的包已经是更新过的源 systemctl start nginx 启动 nginx systemctl enable nginx 将 nginx 设置为开机启动 完成安装在浏览器访问主机 ip ,看看是否能打开。 5.安装PHP7 rpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm 安装php7的rpm包 yum search php7 查询下自己的php7是哪个版本以及扩展库,例如:php70w、php71w、php72w、php70w-fpm等 yum install php70w 以自己的包为准 yum install php70w-openssl php70w-commonphp70w-fpm php70w-mysql php70w-mysqld php70w-pdo 安装PHP7的扩展库的版本号和PHP7的版本对应,也就是 php70w 的版本对应同版本的扩展库 php70w-fpm等。 6.安装Mysql wget http://dev.mysql.com/get/mysql57-community-release-el7-8.noarch.rpm 下载mysql源安装包 rpm -ivh mysql57-community-release-el7-8.noarch.rpm 安装mysql源 yum -y install mysql-server 安装mysql service mysqld start 或 systemctl start mysqld 启动mysql服务器 systemctl status mysqld 查看mysql状态 systemctl enable mysqld systemctl daemon-reload 开机启动 grep 'temporary password' /var/log/mysqld.log mysql安装完成之后,在/var/log/mysqld.log文件中给root生成了一个默认密码。通过上面的方式找到root默认密码( :后面为密码),然后登录mysql进行修改 mysql -uroot -p 按回车,输入刚才的临时密码,进入mysql来修改密码 set global validate_password_policy=0; mysql5.7默认安装了密码安全检查插件(validate_password),默认密码检查策略要求密码必须包含:大小写字母、数字和特殊符号,并且长度不能少于8位。否则会提示ERROR报错。 此处代码用来修改密码强度:0 or LOW(密码任意,但长度在 8 位或以上)。 set global validate_password_length=4; 设置的密码少于8位,请执行上述命令(最少是4) set password for 'root'@'localhost'=password('新密码'); 执行此代码修改mysql登陆密码 GRANT ALL PRIVILEGES ON *.* TO 'yourname'@'%' IDENTIFIED BY 'YourPassword@123' WITH GRANT OPTION; 添加远程登录用户,默认只允许root帐户在本地登录,如果要在其它机器上连接mysql,必须修改root允许远程连接,执行上述代码。 7.配置php、nginx 配置php vim /etc/php.ini 修改 php.ini 把 cgi.fix_pathinfo 的值改为0 ,前面有 ;的话去掉,大约在763行,进入文件后 输入 :763 定位过去。 vim/etc/php-fpm.d/www.conf 修改 www.cong 修改两处 listen.owner = nobody listen.group = nobody 这两行前面的 ;去掉 user = apache group = apache 将apache 更换成 nginx ,保存后退出( :wq ) systemctl start php-fpm systemctl enable php-fpm 启动PHP,并将它设置为开机启动。 配置nginx vim /etc/nginx/nginx.conf 打开配置文件 server { listen 80; server_name 127.0.0.1:9000; root /www/; index index.php index.html index.htm # Load configuration files for the default server block. include /etc/nginx/default.d/*.conf; location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_param SCRIPT_FILENAME /www/$fastcgi_script_name; include fastcgi_params; } location / { } error_page 404 /404.html; location = /40x.html { } error_page 500 502 503 504 /50x.html; location = /50x.html { } } 依照这个格式改,listen 监听端口,server_name 项目网址(默认设置127.0.0.1:9000),root 项目路径;index 服务器按顺序找首页文件,前面的没有往后找,玩php就可以把 index.php放前面。 localtion 中把fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 中的 $document_root 改为 项目地址。 在项目文件路径下写个 info.php <?php echo phpinfo() ?> 保存退出后,在浏览器输入主机外网 ip/info.php ,查看下是否成功。

优秀的个人博客,低调大师

Android开发实践:自定义带消息循环(Looper)的工作线程

1. 首先,我们完成一个简单的线程框架。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public class LooperThread{ private volatile boolean mIsLooperQuit= false ; private ThreadmThread; public void start(){ if (mThread!= null ){ return ; } mIsLooperQuit= false ; mThread= new Thread(mLooperRunnable); mThread.start(); } public void stop(){ if (mThread== null ){ return ; } mIsLooperQuit= true ; mThread= null ; } protected RunnablemLooperRunnable= new Runnable(){ @Override public void run(){ while (!mIsLooperQuit){ } } }; } 如上述代码所示,mLooperRunnable.run()循环执行线程任务,mIsLooperQuit则是线程退出循环的条件。下面,我们将添加消息的发送和处理代码。 2. 添加线程循环的消息发送和处理代码 (1) 定义消息结构体,创建消息队列 1 2 3 4 5 6 7 8 public class LooperThread{ private Queue<Message>mMessageQueue= new LinkedList<Message>(); public static class Message{ int what; } } (2) 创建互斥锁和条件变量 1 2 3 4 5 public class LooperThread{ private LockmLock= new ReentrantLock(); private ConditionmCondition=mLock.newCondition(); } (3) 创建发送消息的函数 1 2 3 4 5 6 7 8 9 10 //发送消息,由外部其他模块调用,发送消息给线程 public void sendMessage(Messagemessage){ if (mThread== null ){ return ; } mLock.lock(); mMessageQueue.add(message); //添加消息到消息队列 mCondition.signal(); //通知线程循环,有消息来了,请立即处理 mLock.unlock(); } (4) 创建处理消息的函数 1 2 3 4 //处理消息,由线程内部调用 public void handleMessage(Messagemessage){ //这里可以通过一个Callback来回调监听者 } (5) 在mLooperRunnable.run()循环中解析消息 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 protected RunnablemLooperRunnable= new Runnable(){ @Override public void run(){ while (!mIsLooperQuit){ mLock.lock(); Messagemessage= null ; try { while (!mIsLooperQuit&&mMessageQueue.isEmpty()){ mCondition.await(); //没有消息到来则休眠 } message=mMessageQueue.poll(); } catch (InterruptedExceptione){ e.printStackTrace(); } finally { mLock.unlock(); } handleMessage(message); } }; } (6) 修改线程的Stop()函数,唤醒休眠的消息循环 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public void stop(){ if (mThread== null ){ return ; } mIsLooperQuit= true ; mLock.lock(); mCondition.signal(); mLock.unlock(); mMessageQueue.clear(); mThread= null ; } 到这里,一个基本的带有消息循环的线程类封装就完成了,相信大家应该从编写这段代码的过程中,理解了系统是如何实现消息循环的。 本文转自 Jhuster 51CTO博客,原文链接:http://blog.51cto.com/ticktick/1565272,如需转载请自行联系原作者

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册