Java /弱引用:弱引用.get不为null,而没有其他更强的引用将其保存

如何解决Java /弱引用:弱引用.get不为null,而没有其他更强的引用将其保存

这是我非常简单的代码:

class UpdateAlertActivity extends Activity {
    O o ;
    WeakReference<O> _o ;
    ArrayList<O> arr = new ArrayList<>();

    static class O {
        private String l ;

        public O(String l) {
            this.l = l ;
        }
    }

    void test()
    {
        arr.clear();
        Runtime.getRuntime().gc();
        Log.i(LOG_TAG,"breakpoint");
    }

    @Override
    protected void onResume()
    {
        super.onResume();

        o = new O("hello");
        arr.add(o);

        _o = new WeakReference<>(o);


        test(); 
    }
}

当我在test()方法中清除数组时,我在断点处将_o.get()设为null,但事实并非如此。当我在debbuger中看到o所在的位置时,它仅在弱引用_o中显示了我,而我认为在没有其他强引用的情况下,会使用弱引用来释放其实例。 ..

我在StackOverflow上看到我错过了调用GC的记录,但是如您所见,调用它在我的程序中没有任何作用。

编辑: 即使这个超级简单的代码也无法正常运行,这也没有道理...

O o = new O("lol");

WeakReference<O> _o = new WeakReference<>(o);

Log.i(LOG_TAG,"1:" + _o.get().toString());

o = null ;

Log.i(LOG_TAG,"2:" + _o.get().toString());

System.gc();
Log.i(LOG_TAG,"3:" + _o.get().toString()); // output not null here 

EDIT2: 我想使用GC,因为在另一个静态类中,有一个名为lastUpdates的数组,该数组有时由服务器通过TCP发送的应用程序更新填充。

我的所有活动都观察到该lastUpdate数组(通过实现Observer / Observable接口),并且在对其进行更改时,将通知所有这些事件,并使用新到达的更新列表作为参数调用特定的函数onUpdate(ArrayList u)。此功能仅在恢复活动后才处理更新(活动睡眠期间更改UI会导致应用崩溃)。

如果整个应用程序正在“休眠”(例如,用户在设备菜单中),我希望仅第一个活动醒来才能处理新更新。

为此,我在活动类中创建了一个数组pendingPersistentUpdates,该数组存储活动睡眠时已捕获的所有更新的弱引用。当第一个活动唤醒时,在应用程序休眠期间捕获的更新仍在lastUpdates数组中,因此我希望存储在pendingPersistentUpdates活动道具中的弱引用可以返回实际更新,因此我的活动可以对它们进行UI处理,在onResume

我期待着这种情况:

  • 活动A跑步,活动B暂停(例如,在活动A后面)
  • 应用收到更新U。所有活动(A和B)都将得到通知。因为正在运行更新,所以按预期处理更新。 B已将此更新存储在其pendingPersistentUpdates中,因为它已暂停。
  • 暂停后,用户返回到B。在暂停时,将清除lastUpdates数组,因此B pendingPersistentUpdates中更新的弱引用将返回null
  • B恢复,但是pendingPersistentUpdates个弱引用为空(lastUpdates已被清除),因此未处理U。

但是,由于lastUpdate.clear()不会触发GC,因此B pendingPersistentUpdates个更新仍然存在,并且需要第二次处理(不希望有这种行为)

解决方法

不可能强制垃圾收集器运行。 Runtime.getRuntime().gc()只是System.gc()的别名,两者都只是一个提示(请阅读文档;他们提到了这一点)。特别是,调用gc()通常意味着该收集将在其他某个线程中进行;因此,它更是收集者的“开始标志”; gc()不必暂停并等待gc完成一个完整的周期,它只是告诉gc启动一个。同样,尽管不能保证,Thread.sleep(10000L);使得您更有可能看到GC调用的效果。

WeakReference仅保证此对象的存在不会妨碍它引用的对象的任何垃圾回收。就这样。当唯一通过WeakReference对象到达目标对象的方法时,它不会立即丢失其目标对象。这将在以后发生(实际上,发生在对象被GCed之前 :首先,收集器将清除所有weakref,而稍后,某个对象所占用的内存将真正可以自由使用) 。因此,您在调试器中观察到的内容(唯一的途径就是通过该WR来访问该对象)并不是天生的。

还请注意,调试器本身可能是问题。仅仅在那里并观察它就会产生效果(因此请确保您也不要在运行它)。

如果您希望GC更加努力,则可以分配一些相当大的数组并暂停线程,这会有所帮助,但是您无法做任何保证保证 GC的运行。如果要观察,请使用java -verbose:gc restOfArgsHere运行Java,并注意控制台。如果确实发生了GC,您将看到它。

但是。

您粘贴的代码甚至无法编译,这表明您要么只粘贴了一半,要么“为了清楚”对其进行了编辑(通常是一个坏主意,最好精确粘贴要使用的内容!)。特别是,您编写了o = new O("hello");,但是o并未在任何地方定义。 如果这是您课堂上的一个字段,则意味着完全不能收集该参照对象!所以您可能需要检查一下。使那个O o = new O("hello");而不是你所拥有的。假设您正确阅读了调试器,并且调试器运行正常,不是吗,但是很可疑。

,

仅向垃圾回收器建议向系统调用,以释放内存,但不会显式强制使用它。这意味着如果有足够的内存,收集实际上可能不会发生。

https://developer.android.com/reference/java/lang/System#gc()

调用gc方法表明Java虚拟机在回收未使用的对象上花费了很多精力,以便使它们当前占用的内存可供快速重用。当控件从方法调用返回时,Java虚拟机将尽最大努力从所有丢弃的对象中回收空间。

请注意下一个句子“ gc方法表明Java虚拟机会花费更多精力来回收未使用的对象”

内部,垃圾收集器使用启发式/阈值来决定何时收集未使用的对象,因此,基本上,JVM何时需要内存。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res