概述
java程序员是不需要考虑垃圾回收的,这是因为在虚拟机的自动内存管理下实现了内存回收。如果出现了内存泄露或者溢出,在不了解虚拟机的内存模型的情况下,很难排查错误。
内存溢出:out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;
内存泄露:memory leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。
java内存模型
线程私有的是:程序计数器、本地方法栈、虚拟机栈
线程共享:堆、方法区、直接内存
程序计数器
程序计数器是一块较小的内存区域,可以看作是当前线程所执行的行号指示器。字节码解释器通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转都依赖程序计数器的实现。
同时线程切换后恢复到原来的正确的执行位置也需要程序计数器。
程序计数器不会抛出outofmemoryereor错误
java虚拟机栈
java虚拟机展也是线程所私有的。生命周期和线程一样。描述的是java方法执行的内存模型,每次方法调用的数据都是通过栈来传递的。
java虚拟机栈实际上是由一个个栈帧组成、每个栈帧都拥有局部变量表、操作数栈、动态链接、方法出口等信息。每一次方法调用都会有一个对应的栈帧被压入java栈,函数调用结束后栈帧弹出。
本地方法栈
和虚拟机栈发挥的作用相似,但是本地方法栈为虚拟机使用到的native方法服务、而虚拟机栈是为java方法服务。hatspot虚拟机将两者合二为一。
堆
java虚拟机中内存最大的一块,是所有线程共享的一块内存区域。目的是存放对象实例,所有的对象实例和数组都在这里分配内存
主要的垃圾收集也是在这里进行的,所以被称为GC堆(Garbage Collect Heap),从垃圾回收的角度看,堆分为新生代和老年代,再细致一点是eden空间、From Survivor、To Survivor空间,这样划分的目的是为了更好的进行内存回收
对象首先会被分配在新生代中,随着垃圾回收的轮数增加他的年龄会增加,如果到了某个值会分配到老年代中。
方法区
是各个线程共享的区域,主要加载被虚拟机加载的类信息、常量、静态变量。
直接内存
直接内存不是虚拟机运行的一部分、也不是虚拟机规范中的内存区域,但是这部分内存也被频繁的使用,而且也可能导致内存溢出的异常出现