V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
wangsunng
V2EX  ›  Java

百度面试题,大伙给点思路

  •  
  •   wangsunng ·
    lenve · 110 天前 · 6676 次点击
    这是一个创建于 110 天前的主题,其中的信息可能已经有所发展或是发生改变。

    写一段 java 代码,稳定的触发两次 young GC ,然后触发一次 full GC ,然后又是两次 young GC 。

    关键是稳定触发

    21 条回复    2024-08-07 18:29:18 +08:00
    xuld
        1
    xuld  
       110 天前
    如果有人能回答:“如何强制触发一次 young GC”和“如何强制触发一次 full GC”。但不能回答上面的面试题。
    请问这个人面试通过还是不通过?
    expkzb
        2
    expkzb  
       110 天前
    在 Java 中,垃圾收集器的行为通常是由 JVM 的垃圾收集策略和配置决定的,而不是由应用程序直接控制。然而,你可以使用`System.gc()`方法来建议 JVM 进行垃圾收集,但请注意,这个方法并不保证 JVM 一定会执行垃圾收集,也不保证垃圾收集的类型( Young GC 或 Full GC )。

    以下是一个 Java 代码示例,它尝试触发两次 Young GC 和一次 Full GC ,然后再触发两次 Young GC 。但请记住,这只是一种尝试,实际的行为将取决于 JVM 的实现和当前的内存使用情况。

    ```java
    public class GCTrigger {

    public static void main(String[] args) {
    // 尝试触发两次 Young GC
    for (int i = 0; i < 2; i++) {
    System.gc(); // 建议 JVM 进行垃圾收集
    System.runFinalization(); // 建议 JVM 执行可到达对象的终结方法
    try {
    // 等待一段时间,让 JVM 有机会执行垃圾收集
    Thread.sleep(100);
    } catch (InterruptedException e) {
    Thread.currentThread().interrupt();
    }
    }

    // 尝试触发一次 Full GC
    System.gc(); // 再次建议 JVM 进行垃圾收集

    try {
    // 等待一段时间,让 JVM 有机会执行垃圾收集
    Thread.sleep(100);
    } catch (InterruptedException e) {
    Thread.currentThread().interrupt();
    }

    // 尝试再次触发两次 Young GC
    for (int i = 0; i < 2; i++) {
    System.gc();
    System.runFinalization();
    try {
    Thread.sleep(100);
    } catch (InterruptedException e) {
    Thread.currentThread().interrupt();
    }
    }
    }
    }
    ```

    这段代码通过调用`System.gc()`和`System.runFinalization()`来建议 JVM 执行垃圾收集,并使用`Thread.sleep()`来等待一段时间,以便 JVM 有时间响应这些请求。然而,再次强调,这种方法不能保证垃圾收集的类型或次数。

    如果你需要更精确地控制垃圾收集的行为,你可能需要使用特定的 JVM 参数来配置垃圾收集器,或者使用更高级的 JVM 监控和诊断工具来分析和优化垃圾收集的性能。
    wpblank
        3
    wpblank  
       110 天前 via Android
    应该是考察特定内存大小下,gc 触发时机吧,照着规则一直 new 特定大小的对象就行了吧
    wangsunng
        4
    wangsunng  
    OP
       110 天前
    @expkzb 这个并不能稳定触发,因为无论是 System.gc(); 还是 System.runFinalization(); 都只是建议 GC ,并不能保证会发生 GC ,这个题目的难点就在这里。
    wangsunng
        5
    wangsunng  
    OP
       110 天前
    @wpblank 我的思路也是这样,指定运行内存大小和新生代大小之后添加大对象,但是又有一个问题,比如新生代内存有 5M ,新创建的对象是 3M ,按理说不需要 GC ,但是有可能存在内存碎片,导致没有连续的 3M 内存,那么这个时候也可能会触发一次 YoungGC ,内存碎片这种事程序员又不可控
    quantal
        6
    quantal  
       110 天前
    给一个 gpt4o 的回复
    要稳定地触发两次 Young GC 、一次 Full GC ,然后再触发两次 Young GC ,可以通过精确控制堆内存分配来实现。下面是一个示例代码,该代码通过分配和释放对象来控制垃圾回收的发生:
    public class GCDemo {

    private static final int _1MB = 1024 * 1024;

    public static void main(String[] args) throws InterruptedException {
    // 1. 分配足够的内存来触发两次 Young GC
    byte[] allocation1, allocation2, allocation3;
    allocation1 = new byte[2 * _1MB]; // 第一次分配
    allocation2 = new byte[2 * _1MB]; // 第二次分配
    allocation3 = new byte[2 * _1MB]; // 触发第一次 Young GC

    // 2. 再次分配内存,确保触发第二次 Young GC
    allocation1 = new byte[2 * _1MB];
    allocation2 = new byte[2 * _1MB];
    allocation3 = new byte[2 * _1MB]; // 触发第二次 Young GC

    // 3. 分配大对象,触发 Full GC
    allocation1 = new byte[4 * _1MB];
    allocation2 = new byte[4 * _1MB]; // 触发 Full GC

    // 4. 再次分配内存,确保触发两次 Young GC
    allocation1 = new byte[2 * _1MB];
    allocation2 = new byte[2 * _1MB];
    allocation3 = new byte[2 * _1MB]; // 触发第三次 Young GC

    allocation1 = new byte[2 * _1MB];
    allocation2 = new byte[2 * _1MB];
    allocation3 = new byte[2 * _1MB]; // 触发第四次 Young GC

    // 程序结束,等待手动触发 Full GC
    System.gc();
    }
    }
    为了确保该代码按预期运行,你需要使用适当的 JVM 参数来配置堆大小和垃圾收集器。例如:
    java -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:+UseSerialGC GCDemo
    yuankui
        7
    yuankui  
       110 天前   ❤️ 8
    茴香豆雕花
    pangdundun996
        8
    pangdundun996  
       110 天前
    问了一下 GPT ,大致思路是:
    1 )设置 jvm 参数:xms 、xmx 、新生代比例之类的
    2 )然后代码中分配对象,先填满新生代的一半,然后继续分配两次,触发两次 young gc
    3 )取消所有对象引用,触发 gull gc ,因为后续两次分配导致有对象晋升到 old gen
    4 )重复第二步,触发两次 young gc
    中间通过 sleep 来控制流程
    JasonLaw
        9
    JasonLaw  
       110 天前 via iPhone
    这样的问题有什么意义?😅
    jixiangqd
        10
    jixiangqd  
       110 天前
    @JasonLaw #9 意义还是有点,看你是否了解 jvm 的内存管理细节,而且有实践经验
    FreeWong
        11
    FreeWong  
       110 天前   ❤️ 4
    这么在意垃圾回收,还用什么 java
    securityCoding
        12
    securityCoding  
       110 天前
    @JasonLaw 没有任何意义...zgc 一把梭
    amon
        13
    amon  
       110 天前
    哈啰面试官,你能回答这个问题吗:
    模拟掌管一个公司,
    先 miss 吴恩达,
    后 miss 陆奇,
    还 miss 了 Claude 创始人 Dario Amodei 。

    然后的百度 AI 还发展这个样的。
    cc666
        14
    cc666  
       110 天前
    很久没写 java 了,但我认为这个问题的本意可能只是考察对 GC 的详细了解程度,设置各种代的大小,但是本质上来看个人认为是做不到的,只能写出来粗看之下正确的代码,并且这个代码里只能有基本数据类型和数组,因为只要你的代码中存在任何不是你自己写的引用对象,那么这段代码的内存占用就是你完全不可控的,你不可能知道所有被引入的包在类加载的时候生成的对象的数量,就一个 java 在运行时自动导入的 java.lang 包就够吃一壶的了,你让谁计算这些包在导入的时候生生了多少个,多大的内存对象,更不可能控制相关变量的 GC ,从而调参和精心构造你自己申请的内存大小就没有意义,并且 GC 本身就在一个线程里,你无法精确控制 GC 何时运行。

    就 java.lang 包就够想精确实现这个的人喝一壶的了,更别说真实的项目了,个人认为是傻逼面试题而已。
    xing7673
        15
    xing7673  
       110 天前
    @quantal 还是强调一下,v 站禁止 ai 回复,用 ai 发言要慎重。
    wow0o
        16
    wow0o  
       110 天前
    这个问题本身还挺有意思的。 可以让新老生代的实践不再那么镜花水月
    ZZ74
        17
    ZZ74  
       110 天前
    代码不是重点,jvm 参数才是重点。
    首先要确定垃圾收集器用哪个,因为这决定了 Young Old 的比例,CMS 通常是 1:2 ,G1 是百分比。因为 G1 的百分比,以及 region 大小等可能直接导致直接分配到了 Old 。
    通过 6 楼 new byte[]来控制对象大小
    通过控制堆大小 Xms ,Xmx ,和新旧比例来控制 YGC
    通过控制直接分配到老年代的阈值 控制 full GC

    最关键的得对垃圾收集器的行为细节了如指掌才行,比如有大对象直接进老年代,但是没看过细节你怎么知道它不会顺手执行个 YGC
    109021017
        18
    109021017  
       110 天前
    @amon 面试官: 关我屁事, 关你屁事
    feiyan35488
        19
    feiyan35488  
       110 天前
    @JasonLaw 互联网八股文
    incubus
        20
    incubus  
       109 天前
    @wangsunng 定时器?
    sagaxu
        21
    sagaxu  
       109 天前
    .net 和 Go 就没这么多屁事
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5287 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 47ms · UTC 09:40 · PVG 17:40 · LAX 01:40 · JFK 04:40
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.