堆栈溢出的一些看法
jvm的内存分配
1.寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制.
2. 栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符串常量对象存放在常量池。)
3. 堆:存放所有new出来的对象,和定义的数组
4. 静态域:存放静态成员(static定义的)
5. 常量池:存放字符串常量和基本类型常量.
~~ ~
String s1 = "china";
String s2 = "china";
String s3 = "china";
String ss1 = new String("china");
String ss2 = new String("china");
String ss3 = new String("china");
~
如上图代码我们队 堆,栈,常量池的分类如下
堆溢出可以分为以下两种情况(OutOfMemoryError:java heap space):
1、内存泄漏
内存泄漏是指对象实例在新建和使用完毕后,仍然被引用,没能被垃圾回收释放,一直积累,直到没有剩余内存可用
2、内存溢出
内存溢出是指当我们新建一个实力对象时,实例对象所需占用的内存空间大于堆的可用空间。
与栈相关的内存异常有两个():
1、StackOverflowError(方法调用层次太深,内存不够新建栈帧)
,出现此种情况是因为方法运行的时候,请求新建栈帧时,栈所剩空间小于战帧所需空间。线程请求的栈深度大于虚拟机所允许的最大深度
例如,通过递归调用方法,不停的产生栈帧,一直把栈空间堆满,直到抛出异常 :
2、OutOfMemoryError(线程太多,内存不够新建线程)
虚拟机在扩展栈深度时无法申请到足够的内存空间,单线程不好出现,但是一直建线程就会出现
总结
所以我们日常遇见的堆栈溢出,递归一般就是栈溢出,然后对象太大譬如bitmap,或者内存泄露一般都是堆溢出,但是也不绝对,如下面这个方法 虽然是递归但是由于list添加的太大所以直接就堆溢出了.
private static void stack() {
List list=new ArrayList();
list.add(new byte[5*1024*1024]);
stack();
}