《深入理解java虚拟机》读书笔记(1)- JVM内存基本结构
文章目录
前言
面向的读者:
- 有一定java基础
- 想系统学习JVM基础知识
文章目的: - 自己读书笔记
- 精炼知识点,实现输入输出闭环
一、JVM运行时内存区域
需要注意的是,JVM划分了很多内存区域,这些区域都是逻辑上的。其实在物理上,他们可以是同一块区域或者不块区域。这里,我们只讨论逻辑区域。
- 程序计数器(program counter register): 由JVM 控制,没有定义OOM,主要用来控制程序的执行。多线程情况下,还会记录线程状态。
- 虚拟机栈(Java Virtual Machine Stack): Java 是基于stack的语言,栈是线程私有的。方法执行时,会创建一个stack frame。
- java 堆(java heap): 对象所在的空间,也是垃圾回收的主要场所。线程共有的。
- mataspace: 存放class,常量,即时编译缓存代码等。这里也会回收,但是一般效率不高。不过有时候也会出现溢出情况。FastJson就由一个bug,会导致这里的内存溢出。
- 直接内存(Direct Memory)。JVM之外的一块区域,现在用到的场景就是NIO 里面,作为缓冲区。
二、java对象在内存中是怎样存在的
1. 对象的创建
1.1 对象创建方式
对象创建时,需要为对象分配对应的内存空间。分配空间的方式有两种
- 指针碰撞(Bump the Pointer)
- 空闲列表 (free list)
具体采用哪种分配方式需要,是更具内存空间是否连续来决定的。一般来说,带compact的垃圾收集器,会采用Bump the Pointer。不带compact的垃圾回收器,没法整理内存空间,所以只有使用free list
1.2 考虑多线程的情况
由于堆内存是线程共享的,而且对象的创建是非常平凡的,所以在并发情况下,可能出现指针错位的情况。解决这个问题,可以有两种办法
- CAS 保证原子性
- 本地线程分配缓冲(Thread Local Allocation Buffer, TLAB). 线程创建一块缓冲区,当然这个区域是线程独有。只有这块区域不够时,才去线程外申请新的空间。
到目前为止,对象只是有了他的内存空间,但是这个空间里面要存什么东西,还没有开始。下一步就是设置对象的头信息,调用< init>() ,调用构造函数。
2. 对象的内存布局
3. 怎么找到内存中的对象
- 句柄池,对象被移动时,只改变句柄池中的指针数据,reference本身不用移动
- 直接指针,速度快,内存小。
总结
本章主要介绍JVM的内存布局,在后面的章节,会对每一个内存进行详细讲解。另外,书中还有很多实践,相信如果对理论知识完全掌握的情况下,自己写一些case应该没有问题,本文就不做列举。