内存溢出有3种,我们最熟悉的就是堆内存溢出异常,比如我们new一个对象或者数组,如果超出了JVM的heap内存最大限制就会爆出异常
比如:
从这句话我们可以知道,栈内存溢出有2种异常一种是:StackOverflowError、另一种是OutOfMemoryError
StackOverflowError是指【线程】的栈内存不足,导致【线程】抛出了StackOverflowError。
线程的stack是线程独有的,默认大小通常1M,可以通过-Xss来设置,比如-Xss128k,-Xss越大,则线程获得栈内存越大,越难出现栈内存溢出。不过从经验上来讲,1M的栈内存是足够的,如果还出现栈内存溢出,就只能说明程序有问题,常见的就是在线程内过度的进行函数调用,函数调用会消耗栈空间,比如拼命的进行递归调用,这个时候你得考虑在算法上做优化了。
下面是代码演示(仅供参考):
递归函数调用栈开避了7493开始发现Main线程的栈空间不足,所以抛出了main线程的栈空间不足的异常
如果我把-Xss2m那么可开避的函数调用栈会差不多翻一倍
而JVM虚拟机本质上是操作系统上的一个进程,所以他也拥有自己的系统堆空间和栈空间。
JVM的栈空间被所有线程分割成一块一块的,每个线程只占用一块。而JVM的栈空间的最小分配单位由-Xss来决定,没错,-Xss有两个语义, 即定义了每个线程的栈大小,也定义了虚拟机的最小栈内存的分配单位。我们甚至可以估算出,虚拟机可以创建的最大线程数,即操作系统可以分配给进程的最大栈空间大小除以-Xss的值,就可以得到最大活跃线程数。如果先申请的线程没有栈空间可以分配了就会抛出 OutOfMemoryError。表示【JVM虚拟机】的栈空间不足,溢出异常。
下面是演示代码(注意,这个实验可以能会因为JVM申请太多栈内存,导致操作系统因为栈空间不足出现假死。我的内存16G,所以妥妥的):
代码中我设置了-Xss1m
我开启了N多个线程,然后让所有线程等待(持有栈空间,不释放)。
你会发现很快抛出了异常。
如果我设置为-Xss128k
你会发现要等很久才会抛出异常,因为每个线程才128K,所以可以分配的线程变多了,所以for又多运行了几次,才没那么快死机。