栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

相同进程,一个线程OOM,其余线程可以正常运行么?

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

相同进程,一个线程OOM,其余线程可以正常运行么?

有很多文章(有一个文章分别从栈,堆以及1.8之前的永久代,1.8之后的元数据区分别进行了阐述)对这个问题进行了阐述,首先可以确定的是 可以运行
当一个线程抛出OOM(Out Of Memory)异常之后会被停止,会立刻进行GC,内存空间释放,不影响其余的线程。
但是很多测试代码都是往一个线程内的集合存放String数据,所以,当线程停止的时候,这个线程里面的集合就会被清理掉,集合内部的东西自然也会被清理(无根可达)。

但是我们把集合放在全局变量里面呢?或者static修饰的全局变量呢?
对上面的两种情况分别进行了测试,答案依旧是***可以运行***。
按照常理来讲,static是根节点,基本上不会被GC掉的,所以为什么呢?

public class ThreadPoolStr {
    static List list= new ArrayList();
    public static void main(String[] args) throws IOException {
        new Thread(()->{
           while (true){
               Thread.currentThread().setName("添加list");
               Random random = new Random();
               Integer i = random.nextInt(100);
               list.add(new String(i.toString()));
           }
        }).start();
        new Thread(()->{
            Thread.currentThread().setName("测试你好");
            while (true){
                try {
                    Thread.sleep(1000);
                    System.out.println("你好");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        new Thread(()->{
            Thread.currentThread().setName("测试list以及里面的内容有没有被GC");
            while (true){
                try {
                    Thread.sleep(1000);
                    System.out.println(list.size());
                    System.out.println(list.get(0));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

上面几个线程的打印结果
当添加线程OOM之后
测试你好线程 依旧坚挺
测试list内容是否完整,是否被GC 打印结果时没有被GC。
显然我想不明白为啥了,为什么内存明明已经不够了,另外的线程却并没有收到影响?
是因为栈分配?
那我们试试往线程里面放一个大对象?让他不会往栈里面分配,往TLAB里面分配,直接往新生代丢甚至直接丢入old区?
(TLAB 线程本地分配 占用的也是Eden的内存 堆内存满了 显然这里也不能分配了)
于是我们设置写一个不可以栈内存分配的对象 让其余的线程操作(只要不是线程私有的,就不可以栈上分配,也不可以TLAB)

public class ThreadPoolStr {
    static List list = new ArrayList();
    //sir是我自定义的一个类 显然这个是堆内存分配的
    static SIR sir = new SIR();

    public static void main(String[] args) throws IOException, InterruptedException {

        new Thread(() -> {
            while (true) {
                Thread.currentThread().setName("添加list");
                Random random = new Random();
                Integer i = random.nextInt(100);
                list.add(new String(i.toString()));
            }
        }).start();
        new Thread(() -> {
            Thread.currentThread().setName("测试你好");
            while (true) {
                try {
                    Thread.sleep(1000);
                    List list = new ArrayList<>();
                    list.add(new SIRResult());
                    sir.setList(list);
                    System.out.println(sir.toString());
                    System.out.println("你好");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        new Thread(() -> {
            Thread.currentThread().setName("测试list以及里面的内容有没有被GC");
            while (true) {
                try {
                    Thread.sleep(1000);
                    System.out.println(list.size());
                    System.out.println(list.get(0));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        Thread.sleep(5000);
        sir = new SIR();
        sir.setId("213123");
        System.out.println("sir"+sir.hashCode());
    }
}

上面的测试,依旧是不会受到影响。
为了防止我代码的问题 我有关闭了逃逸分析,标量替换什么的 绝对不会本地分配
-XX:-DoEscapeAnalysis -XX:-EliminateAllocations -XX:-UseTLAB
结果依旧是 一个线程OOM 其余线程不会收到影响。
我又用测试你好线程测试了一下往list继续新增,增加一条都不行了,会OOM,再次说明list 没有被GC。
所以无论如何测试
最后的结果肯定是
同一个进程,单线程发生OOM,绝对不会影响到其余的线程。
但是为啥子 会出现我这次测试的情况,我不理解,还希望能人大佬们来解答。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/703643.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号