当前位置: 首页 > 面试题库 >

是WeakHashMap不断增长,还是清除垃圾密钥?

张唯
2023-03-14
问题内容

我试图将其WeakHashMap用作Set弱引用的并发。

    this.subscribers =
            Collections.synchronizedSet(
                    Collections.newSetFromMap(
                            new WeakHashMap <>()
                    )
            );

当元素进入垃圾收集时,我的集合继续将其报告为收集的一部分。因此,地图似乎正在不断增长。

该文档说:

放弃键后,其条目将有效地从地图中删除,…

但是实际上似乎并非如此。

有没有WeakHashMap清除碎屑的地方?


问题答案:

是的,WeakHashMap可以清除碎屑。用于垃圾回收的密钥不再以大小报告。但是您必须等待垃圾收集真正发生。

似乎您对将对象进行垃圾回收的想法不正确。也许您的对象已成为垃圾收集的 候选
对象,但尚未被收集。尝试调用垃圾收集器,等待片刻完成。但是请记住,对的调用System.gc()只是对JVM的建议,根据您的JVM实现和当前的运行时场景,可能会被忽略。

这是一个完整的示例应用程序。请注意,该Set报告报告了size调用Set::remove还是让对象超出范围的减少。

package com.basilbourque.example;

import java.util.Collections;
import java.util.Set;
import java.util.UUID;
import java.util.WeakHashMap;

public class WeakHashMapExercise {

    public static void main ( String[] args ) {
        WeakHashMapExercise app = new WeakHashMapExercise();
        app.doIt();
    }

    private void doIt ( ) {
        Set < UUID > set =
                Collections.synchronizedSet(
                        Collections.newSetFromMap(
                                new WeakHashMap <>()
                        )
                );

        UUID uuid1 = UUID.fromString( "a8ee1e34-cead-11e8-a8d5-f2801f1b9fd1" );
        UUID uuid2 = UUID.fromString( "39bda2b4-5885-4f56-a900-411a49beebac" );
        UUID uuid3 = UUID.fromString( "0b630385-0452-4b96-9238-20cdce37cf55" );
        UUID uuid4 = UUID.fromString( "98d2bacf-3f7f-4ea0-9c17-c91f6702322c" );

        System.out.println( "Size before adding: " + set.size() );

        set.add( uuid1 );
        set.add( uuid2 );
        set.add( uuid3 );
        set.add( uuid4 );

        System.out.println( "Size after adding 4 items: " + set.size() );  // Expect 4.

        set.remove( uuid3 );

        System.out.println( "Size after removing item # 3: " + set.size() );  // Expect 3.

        uuid2 = null;  // Release that UUID to garbage-collection.

        // That released object may still appear in our `Set` until garbage collection actually executes. 
        System.gc(); // Ask the JVM to run the garbage-collection. Only a suggestion, may be ignored.
        try {
            Thread.sleep( 1_000 );  // Wait a moment, just for the heck of it.
        } catch ( InterruptedException e ) {
            e.printStackTrace();
        }

        System.out.println( "Size after making garbage of item # 2: " + set.size() );  // Expect 2.

        for ( UUID uuid : set ) {
            System.out.println( uuid.toString() );
        }


    }
}

看到此代码在IdeOne.com上实时运行。

添加前大小:0

添加4个项目后的大小:4

移除项目3后的尺寸:3

制作项目#2的垃圾后的尺寸:2

在我的情况下,使用Java的10.0.2版本的OpenJDK基础的祖鲁JVM从阿祖尔系统,垃圾收集器似乎在我的请求被激活。如果我将延迟或System.gc通话延迟一秒钟,那么报告的最后一个大小将保持不变,3而不是预期的大小2

您甚至可以在IdeOne.com上实时运行此代码时看到此行为。请注意,下面的最后一项是,3但是上面的是2

添加前大小:0

添加4个项目后的大小:4

移除项目3后的尺寸:3

制作项目#2的垃圾后的尺寸:3



 类似资料:
  • 这是一个内存数据安全问题。 java垃圾收集是否安全地清除垃圾数据? 显然,在一个数据块被垃圾收集后,我不能再检索它了,但黑客还能通过内存转储来检索数据吗?

  • 问题内容: 与同事进行了讨论。当诸如c#或java垃圾之类的语言收集诸如字符串之类的对象并将其返回到堆时,它们是否也清除了该内存块,例如用0或1覆盖? 我的假设是,除非按原样返回该块,除非使用诸如带有带有finalize重载的securestring之类的类将该块清零。 问题答案: 实际上,不,这不会发生。覆盖刚刚释放的内存需要花费时间,因此会有性能损失。“安全”之类的物体SecureString

  • 问题内容: 我正在使用实现缓存。我想知道是否要遍历此映射的键,同时垃圾回收器正在主动从此映射中删除键,我会收到吗?我不这么认为,因为据我所知,并发修改异常是由于应用程序代码中的错误而发生的,开发人员忘记了同一个映射是由其他线程共享/使用的,因此在这种情况下,应该不会发生。但是想知道当WeakHashMap不同步时JVM将如何处理吗? 问题答案: 正如bkail所说,当GC从a中“删除”一个条目时,

  • 问题内容: 简短形式:CMS垃圾收集器似乎无法收集数量不断增加的垃圾;最终,我们的JVM填满,应用程序变得无响应。通过外部工具(JConsole或)强制GC 清理一次。 更新:该问题似乎与JConsole的JTop插件有关。如果我们不运行JConsole,或者在没有JTop插件的情况下运行它,则该行为消失。 (技术说明:我们正在Linux 2.6.9机器上运行32位Sun JDK 1.6.0_07

  • 主要内容:JEP 189 : Shenandoah:一个低暂停时间的垃圾收集器(实验性),JEP 346 : 及时返回未使用的已提交内存,JEP 344:可中止的混合集合Java 12 为其垃圾收集算法引入了多项增强功能。 JEP 189 : Shenandoah:一个低暂停时间的垃圾收集器(实验性) 引入了一个实验性的低暂停时间垃圾收集器 Shenandoah 以减少 GC 暂停时间。它与运行 Java 线程并行工作。这有助于减少 GC 对堆大小的依赖性并使其保持一致。现在垃圾收集暂停时间对于

  • 问题内容: 什么是JavaScript垃圾回收?为了编写更好的代码,对于Web程序员来说,了解JavaScript垃圾回收有什么重要意义? 问题答案: 从该页面引用: JScript使用了非世代的标记清除垃圾收集器。它是这样的: 每个“范围内”的变量都称为“清除剂”。清道夫可以指数字,对象,字符串等。我们维护一个清道夫列表- 变量进入作用域时将移入scav列表,超出范围时将其移出scav列表。 垃