有很多文章(有一个文章分别从栈,堆以及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,绝对不会影响到其余的线程。
但是为啥子 会出现我这次测试的情况,我不理解,还希望能人大佬们来解答。



