美文网首页
美团面试真题之一个线程OOM,进程里的其他线程还能运行吗?

美团面试真题之一个线程OOM,进程里的其他线程还能运行吗?

作者: happy518 | 来源:发表于2018-12-20 15:37 被阅读0次

一个进程有3个线程,如果一个线程抛出OOM,其他两个线程还能运行吗?

答案是还能运行

不瞒大家说,正在面试中,我遇到这一题,我估计也会答错,因为我初看这一题的时候,觉得是在考察JVM的内存结构,我第一反应是OOM常见情况堆内存溢出,也就是下面的这种异常

java.lang.OutOfMemoryError:java heap space

多线程中栈与堆是公有还是私有的

在多线程环境下,每个线程拥有一个栈和一个程序计数器,栈和程序计数器用来保存线程执行历史和线程执行状态,是线程私有的,堆是由用一个进程内多个线程共享的。

测试代码伪代码如下:

一个线程去构造堆内存溢出,每隔ls申请一次堆内存。

package com.ypb.oom;

import com.google.common.collect.Lists;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;

/**
 * @className ThreadOOMTest
 * @description 测试一个线程出现OOM,同进程下的其他线程还能继续运行吗?
 * @author yangpengbing
 * @date 22:12 2018/12/19
 * @version 1.0.0
 */
@Slf4j
public class ThreadOOMTest {

    public static void main(String[] args) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        int m = 1024 * 1024;
        String name = "oom-thread";

        new Thread(() -> {
            List<byte[]> bytes = Lists.newArrayList();
            while (true) {
                show(format(formatter));
                
                bytes.add(new byte[m]);
                
                sleep();
            }
        }, name).start();

        name = "not-oom-thread";
        new Thread(()->{
            while (true) {
                show(format(formatter));
                sleep();
            }
        }, name).start();
    }

    /**
     * 控制台输出时间和线程名称
     * @param msg
     */
    private static void show(String msg) {
        System.out.println(msg);
    }

    /**
     * 线程休眠1s
     */
    private static void sleep() {
        try {
            TimeUnit.SECONDS.sleep(1L);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 格式化输出的信息
     * @param formatter
     * @return
     */
    private static String format(DateTimeFormatter formatter) {
        return String.format("data {%s}, thread {%s}", LocalDateTime.now().format(formatter), Thread.currentThread().getName());
    }
}

控制台输出的结果:

从日志中可以看出,线程oom-thread线程溢出了,其他线程not-oom-thread线程还在执行中。使用jvisualvm监控下。

设置的jvm参数:

-Xmx32m -Xms32m -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -verbose:gc -XX:+PrintGCDateStamps -Xloggc:E:/gc.log

1

分析gc日志,可以看出老年代的内存使用率达到99.79%。内存使用率已经满了。出现内存溢出。

上面是jvisualvm监控堆内存变化的结果,注意看图上,抛出OOM的时间在14:56:54左右,重点关注这个时间点左右的曲线变化。发现堆使用的数量突然间急速下滑,这代表这一点,当一个线程抛出OOM异常后,它说占用的内存空间会全部被释放掉,从而不会影响其他线程的运行。

这个例子只是演示了堆内存溢出的情况,如果是栈内存溢出,结论也是一样的。

相关文章

网友评论

      本文标题:美团面试真题之一个线程OOM,进程里的其他线程还能运行吗?

      本文链接:https://www.haomeiwen.com/subject/hpiykqtx.html