1、概述
咱们在进行Java开发的时候,不多关心Java的内存分配等等,由于这些活都让JVM给咱们作了。不只自动给咱们分配内存,还有自动的回收无需再占用的内存空间,以腾出内存供其余人使用。可是咱们常常面临的一个问题就是内存泄漏,JVM没法完成回收工做,致使内存占用暴涨,最后可能让程序奔溃。本章主要了解下运行时数据区域分布状况以及溢出异常。java
说明: 本系列多处摘抄《深刻理解Java虚拟机》中内容,主要精简了本书的要点,并叙述本身对本书的理解。本人才疏学浅,文章中有不对的地方,还望批评指教。web
2、运行时数据区域
一、程序计数器
线程私有微信
当前线程所执行的字节码的行号指示器多线程
Java多线程是经过再一个内核中轮流执行实现的,计数器就保证了切换线程的时候能够回到原来正确的执行位置函数
程序计数器必须每一个线程单独一个,是线程私有的内存区域布局
程序计数器是惟一一个JVM没有规范OutOfMemoryError的区域性能
二、Java虚拟机栈(java方法)
线程私有学习
Java方法执行的内存模型,即方法执行时会建立一个栈帧,保存了须要的局部变量表、操做数栈、动态连接、方法出口等信息;spa
线程请求的栈深度>JVM容许的深度时,报StackOverflowError;.net
大多数的JVM能够动态扩展内存,若是没法申请到足够的内存时,报OutOfMemoryError;
三、本地方法栈(native方法)
同Java虚拟机栈
四、Java堆
线程共享
惟一目的:存放对象实例
分类:新生代、老生代,或者Eden空间、From Survior 空间、To Survivor空间
分类目的:更好的回收和分配内存
没有内存完成实例分配,或者不能再扩展,报OutOfMemoryError异常
能够本身配置大小(-Xmx和-Xms)
五、方法区
线程共享
目的:存储类信息、常量、静态变量、即时编译器编译后的代码等数据;
该区内存回收目标:主要针对常量池的回收和对类型的卸载;
没法知足内存分配要求时,报OutOfMemoryError异常
六、运行时常量池
注意:运行时常量池属于方法区
目的:存储编译期生成的各类字面量和符号引用
特征:并不是只有编译期置入Class文件中的常量池内容才能进入运行时常量池,在运行期间也能够置入新的常量,好比String的intern()方法;
没法申请足够内存时,报OutOfMemoryError异常
3、 直接内存
非运行时数据区域内存
Native函数分配堆外内存,堆内的DirectByteBuffer做为这块内存的引用
性能显著提升,避免了Java堆和native之间来回复制数据
4、 对象
一、New对象过程
new指令发出
检查new的参数是否在常量池中存在这个Class的符号引用
检查对应的Class是否已经初始化
若没有则先执行初始化过程
分配内存,检查堆是否规整(垃圾收集器是否带有压缩整理功能决定)
规整:指针碰撞方式分配内存
不规整:空闲列表方式分配内存
内存空间初始化为零值(不包括对象头)
对对象进行重要的配置
执行 < init > 方法
二、对象的内存布局
对象头(Mark Word)
自身运行时数据
GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID
类型指针:肯定对象是哪一个Class的实例
实例数据
存储有效信息,定义的各类字段
相同宽度的字段老是被分配到一块儿
对齐填充
不必定存在
实例数据没有对齐,须要填充
三、对象的访问定位
句柄(reference):
堆中划分句柄池
句柄地址
到对象实例数据的地址
到对象类型的地址
优点:稳定,对象移动时,(如GC时会移动),这个时候只改变指针地址。句柄信息不变,相对稳定;
指针:
直接存储了上述的对象地址
优点:速度快
5、OOM
堆溢出:举例一直new新的实例对象
栈溢出:举例无限循环调用执行某个方法
方法区和运行时常量池溢出:
String.intern():若是常量池已存在,则返回String对象,若是不存在,则先添加到常量池,再返回String对象。
动态定义大量的Class,须要注意内存的回收状况。
6、小结
程序运行时,须要不停的将数据在内存中分配、计算等。JVM将不一样类型的数据放在不一样的位置,这样分工才可以让程序有序的跑起来。咱们所定义的方法,以及new的对象实例都分别存在方法区和堆中,这两个区域是属于内存共享的地方,也就是说任何线程取的都是同样的。可是,由于有线程的存在。因此,咱们须要给线程必要的私有空间。故,在程序运行的时候,咱们经过栈来保存该线程自由的局部变量、引用等,经过程序计数器保存了各个线程的执行位置。这样,在线程切换的时候,才能找到本身的上一次执行位置,继续完成未完成的工做。若是,程序执行过程当中没有足够的空间分配,就报对应的OOM异常。
本文由原做者井方哥独家受权Open软件开发小组发布,著做权归原做者全部。如需转载请联系原做者申请受权。
申请加群交流学习请加主编微信:Jf-1994(井方哥),并备注:姓名-地区-公司-职业-加群。
专一Android开发,欢迎关注open_dev!
本文分享自微信公众号 - Open软件开发小组(open_dev)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。