jvm内存溢出问题,为什么jvm没及时回收。

面试官问了2个问题。

1:内存溢出如何造成的

2:内存溢出前,为什么jvm没去回收。

正在使用中的变量太多了,程序执行自动回收,发现你变量都在使用 无法回收

下面死循环为例,程序一直在生成新变量a,一直占用内存,内存满后自动释放时,你list还在方法内,没有结束,不能释放,就会内存溢出

 List<Integer> list = new ArrayList<Integer>();
while(true){
    int a = 1;
    list.add(a);
}

可以这样回答,那你要看哪种情况的溢出,在JVM的内存模型里,Java栈,Java堆,方法区都定义了OutOfMemoryError的异常,
1、先说Java栈的溢出情况
首先Java栈的结构是线程私有的一排一排的栈桢,每个线程在执行方法时,都会对应一个栈桢的入栈操作,而在Java编程语言规范中,并没有指定
在Java栈进行内存回收的要求,因此也就是说,执行线程越多,或某个线程执行过程中递归调用的层级太多,都会造成可能的栈溢出。这个溢出是
由于进行内存回收导致的
2、Java堆的内存溢出
Java堆定义了内存回收,但也是分情况的,虚拟机会把对象的引用程度分为四种:强引用、弱引用、软引用、虚引用。只要有类似于Object obj =
new Object(); 这样的引用存在,obj对象就永远不会被回收。这是强引用,而弱引用,则是在Java堆空间不足时的优先回收对象,而弱引用只能逃
过一次内存回收,下一次内存回收时一定会回收掉弱引用的对象,而虚引用最弱,这种引用的存在仅仅是为了虚拟机回收对象,这是一种一定会被
回收的对象。因此,Java堆的内存溢出,完全可以归结于程序中出现大量的强引用对象,无法回收。可以通过扩大Java堆的空间来进行优化。
3、方法区的溢出
方法区的溢出要看里面存了什么东西,在java8以前,方法区不只要存储静态变量、字面量,还要存储编译器生成的代码和Class对象,而随着
热部署的出现,程序运行过程中动态加载的类,不会释放旧的类加载器所加载的类,部署次数过多时就会导致方法区的内存不足,同时,如果
程序中出现大量的字符串字面量、静态变量,也会把撑爆方法区,但这种情况比较少,这种情况下的回收一般也可以通过Jvm的选项来调整方法
区的内存大小来进行优化。同时程序也要优化。减少静态变量和字符串字面量的数量。

不好意思,上面四种引用程序的顺序说反了,正确的是下面的:

虚拟机会把对象的引用程度分为四种:强引用、软引用、弱引用、虚引用。

后面一句也描述反了:
而软引用,则是在Java堆空间不足时的优先回收对象,而弱引用只能逃过一次内存回收,下一次内存回收时一定会回收掉弱引用的对象,

JVM并非不想回收而是没办法回收,比方说有100张图片都在被java程序引用,内存马上满了,回收哪一个合适,假设选择一个回收了,应用莫名其妙地出了问题,去哪里找原因呢

溢出就是你要求分配的内存超出了系统能给你的,系统不能满足需求,于是产生了溢出

JVM回收内存只有条件的,根遍历遍历不到的对象才会被回收,如你所说,如果有一些对象一直持有强引用,那么就算JVM内存溢出也不会被回收。

无用的对象,仍然有强引用支撑,所以无法回收,导致内存溢出

系统如果认为文件还有用的话就不会回收

内存溢出:操作系统分配给每个进程的内存是有限的,虚拟机提供参数来设置java堆和方法区这两部分内存的最大值,可以创建线程的数量 = 剩余内存 / 线程的容量所有,若每个线程分配的栈容量(-Xss)越大,可以创建的线程数量就越小,那么,不断的创建线程,把剩余内存逐渐耗尽,当剩余内存不足时,就会抛出内存溢出。
jvm回收:垃圾回收是判断一个对象有没有任何引用与之关联,如果有,就不能被回收,在内存溢出时,jvm肯定要去回收。

什么时候会进行垃圾回收

没有识别出垃圾,就不会回收