一、概述
1.不再需要为每一个new操作去写配对的delete/free代码,不容易出现内存泄露和内存溢出问题
二、运行时数据区域
- 程序计数器:每个线程都有一个(线程私有);唯一一个没有在Java虚拟机规范中规定任何OutMemoryError的内存区域
- Java虚拟机栈:线程私有;描述Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息
- 局部变量表:存放了编译期可知的各种基本数据类(boolean,byte,char,short,int,float,long,double)、对象引用和returnAddress类型。所需的内存空间在编译期间完成分配,方法运行期间不会改变局部变量表的大小
- 本地方法栈(Native Method Stack):与虚拟机栈的区别在于,虚拟机栈为虚拟机执行Java方法服务,而本地方法栈则为虚拟机使用到的Native方法服务
- Java堆:虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。用于存放对象实例。是垃圾收集器管理的主要区域。Java规范规定,Java堆的内存空间不需物理上连续,只需逻辑上连续
- 方法区:各线程共享,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。其内存空间只需逻辑上连续、可以选择固定大小或可扩展、可选择不实现垃圾回收
- 运行时常量池:方法区的一部分。运行时常量池相对于Class文件常量池的另外一个重要特征是具备动态性
- 直接内存:使用Native函数库直接分配堆外内存,可通过存储在Java堆中的DirectByteBuffer对象作为这块内存的应用进行操作
三、HotSpot虚拟机对象
- 虚拟机遇到一条new指令
- 首先检查这个指令的参数是否在常量池中,其代表的类是否已被加载、解析和初始化;若没有,必须先执行相应的类加载过程
- 在堆中为对象分配内存
- 指针碰撞(Bump the Pointer):指针仅移动与对象大小相等的连续距离
- 在使用Serial、ParNew等带Compact过程的收集器采用
- 不能进行指针碰撞,虚拟机就必须维护一个列表来记录哪些内存可用(空闲列表(Free List))
- 使用CMS这种基于Mark-Sweep算法的收集器时采用
- 并发分配内存-解决
- 对分配内存空间的动作进行同步处理
- 按线程划分内存空间:本地线程分配缓存(Thread Local Allocation Buffer, TLAB)
- 将内存空间初始化为零值
- 虚拟机对对象进行必要的设置
- 对象头(Object Header):存放元数据信息、对象的哈希码、对象的GC分代年龄等
- 执行<init>
- 对象的内存布局
- 对象头
- 实例数据:存储对象的有效信息、各类型的字段内容
- 从父类继承下来的也要记录
- HotSpot虚拟机的默认分配策略:longs/doubles, ints, shorts/chars, bytes/Booleans, oops(Ordinary Object Pointers)
- 相同宽度的字段总是被分配到一起
- 对齐填充:仅起到占位符的作用
- 对象的访问定位
- Java程序需要通过栈上的reference数据来操作堆上的具体对象
- 对象访问方式:句柄和直接指针
- 句柄池:reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据和类型数据各自的具体地址信息
- 对像被移动时只需改变句柄中的实例数据指针,reference本身不需修改
- 直接指针:reference存储的是对象地址
- 速度较快:不用指针定位
- OutOfMemoryError异常
- 可能发生的区域:方法区、堆、虚拟机栈、本地方法栈等
- Java堆溢出
- 存储的对象实例占用的内存达到上限
- 参数(-XX:+HeapDumpOnOutOfMemoryError):堆内存满时跳出
- 内存映像分析工具:Eclipse Memory Analyzer
- 参数在Run configuration中设置
- 虚拟机栈和本地方法栈溢出
- HotSpot不区分虚拟机栈和本地方法栈;栈参数(-Xss)
- SatckOverflowError:栈溢出
- 扩展栈失败: OutOfMemoryError
- 单个线程下,无论是栈帧太大还是虚拟机栈容量太小,当内存无法分配时,虚拟机都会抛出StackOverflowError
- 方法区和运行时常量池溢出
- 方法区设置参数:-XX:PermSize和-XX:MaxPermSize
- String.intern():是一个native方法;查看常量池中是否有该String对象,没有则添加到常量池
- 字节码技术:如GCLib;保证动态生成的类可以加载到内存
- JVM动态语言:如Groovy;实现语言的动态性
- 直接内存溢出
- 参数(-XX:MaxDirectMemorySize):默认与Java堆最大值一样