一、为什么要了解JAVA虚拟机
Java程序员把内存控制的权力交给了JVM,一旦出现内存泄漏和内存溢出方面的问题,如果不了解jvm,那么排查十分艰难!
二、jvm运行时数据区
注:其中方法区和堆是所有线程共享的,其它是各自线程私有。
注2:本地方法,也就是native方法,指java方法中,非java语言实现的方法,如用c语言实现。
1、程序计数器
是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。
多线程时,为了线程切换后能恢复到正确的执行位置,每个线程都需要有一个独立的程序计数器。
2、jvm栈
描述的是java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧。
3、本地方法(native mehtod)栈
jvm栈为jvm执行java方法服务中,本地方法栈为jvm使用到的native方法服务。
4、java堆
被所有线程共享,一般内存比较大,在jvm启动时创建。
唯一的目的就是存放对象实例,所有new的对象和数组都要在堆上分配。
一般分为新生代和老年代。
逻辑内存要连续,物理内存可以不连续。
5、方法区
用于存储已被jvm加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
这个区域内存回收目标主要是针对常量池的回收和类型的卸载。
<1>运行时常量池
它是方法区的一部分。
三、HotSpot虚拟机对象探秘
1、对象的创建
<1>语言层面上:new操作
<2>jvm实现:
a.检查类是否被加载、解析和初始化。若没,则执行类加载。
b.分配内存:两种方式,一是指针碰撞,二是空间列表。
可能发生并发问题:可能出现正在给对象A分配内存,指针还没来得及修改,对象B又同时使用了
原来的指针来分配内存。
解决:一是同步机制分配内存;每个线程在堆中预先分配一小块内存,即本地线程分配缓冲 (Thread local Allocation Buffer)
c.初始化分配的内存为零值。
d.jvm对对象进行必要的设置:如属于哪个类、如何才能找到类的元数据信息、对象的哈希码、对象 的GC分代年龄等。这些信息保存在对象的对象头中。
f.new指令执行完之后,会接着执行<init>方法,把对象按照程序员的意愿进行初始化
2、对象的内存布局
注1:实例数据中,相同宽度的字段分配到一起,父类中定义的变量出现在子类之前
注2:对齐是为了对象大小是8字节的整数
3、对象的访问定位------直接指针访问