前言
由于虚拟机自动内存管理机制的帮助下,不需要为每一个new出来的对象,去写delete/free代码。不容易出现内存泄漏和内存溢出的问题,
但是如果一旦出现问题,那将是非常可怕的 ,如果不了解虚拟机是怎么使用内存的,那么排查错误将会成为一项非常艰难的工资。
误区
经常有人讲java内存区分为堆内存和栈内存,这种分发比较粗糙,只能说明大多数程序员最密切的就是这两块
1、Java虚拟机内存分配
1.1、程序计数器(线程私有)
较小的内存空间,可以当做当前线程所执行字节码的行号指示器,每个线程都有自己的行号指示器,互补干扰,因此这部分内存区域也叫作私有区域
1.2、Java虚拟机栈(线程私有)
这里其实就是程序员通俗意义上的栈区,存放基本的数据类型和,对象的引用。(函数多的参数值,局部变量)
每次在方法执行的同时,都会创建一个栈帧,用来存储局部变量表,操作数栈(可以理解成数字),动态链接、方法出入口等信息。每一个方法执行的时候,就对应着一个栈帧在虚拟机栈中入栈和出栈的过程
1.1、这个区域出现的异常情况有两种
1、如果虚拟机请求栈深度大于虚拟机所允许的深度,将抛出 StackOverflowError异常
2、如果虚拟机栈可以动态扩展(当前大部分虚拟机都可以)如果扩展时无法申请到足够的内存,将飘出OutOfMemoryError
1.3、本地方法栈
本地方法栈和虚拟机栈区别是,虚拟机栈为执行的java方法服务,而本地方法栈为Native方法服务。它也会抛出StackOverflowError和OutOfMemoryError异常
1.4、Java堆(线程共享)
Java堆是被所有线程共享的区域,在虚拟机启动时候创建, 此区域的唯一目标就是存放对象实例和数组,
Java堆是垃圾收集器管理的主要区域
1.5、方法区(线程共享)
方法去也是各个线程共享的内存区域,它用于存储以被虚拟机加载的类信息,常亮,静态常量,以及访问修饰符,字段描述,方法描述等,即时编译后的代码等数据。,也叫永久代
1.5.1、运行时常量池
用于存放编译器生成的各种字面量和符号引用
图解
1、所有的内存
2、实战 OutOfMemoryError异常
2.1、java堆溢出
2.1.1、测试代码
1 | public class JavaHeap { |
过一段时间之后报下面错误
1 | Exception in thread "main" java.lang.OutOfMemoryError: Java heap space |
2.1.2、异常分析和解决
可以看到上面的提示Java heap space
java堆内存