Java Virtual Machine

 

java虚拟机,主要分为:

1)类加载子系统

2)jvm运行时数据区(内存)

方法区、堆、栈、程序计数器、本地方法栈

3)执行引擎

 

通过new创建的对象一定是在“堆内存”,

反之,通过“字符串直接量“方式创建的对象,在方法区中

 

String类的intern()方法,会把“字符串”加入到“常量池”中

通过new String(),创建的“字符串对象”是在堆内存中的,所以可以用intern()方法,会把“字符串”加入到“常量池”中

 

 

 

1.运行时数据区,

java虚拟机在执行java程序的时候,把内存分配了若干个数据区域。

 

 

2.jvm运行时结构图

菜鸟的jvm学习总结

 

3.程序计数器(Program Counter Register)

它是程序 “指令”的集合,(包括,分支,跳转,循环,异常处理,线程恢复)

它是一块较小的内存空间,

他的运行速度最快。

线程私有。

 

4.java虚拟机栈

线程私有。

虚拟机栈,描述的是java方法执行的内存模型,每个方法在执行时,都会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出口等。

 

栈中的每一栈帧,都对应一个java方法,

可以说,栈帧 “进栈” 和 “出栈”的过程,就是一个java方法的生命周期

 

每个线程中,都对应一个jvm栈

栈中的每一个栈帧,就是一个java方法

 

人们经常说的“栈”,就是指的,java"虚拟机栈",或者是 java虚拟机栈中的“局部变量表”。

 

局部变量表,中,存放了 8种基本类型 和 对象的“引用地址”,

 

局部变量表的,内存空间,在编译期间,已经可以完全确认,运行期间是不会改变内存空间的大小的。

 

操作数栈:

相当于,数学考试中的“草稿纸”一样,用于记录局部变量表中数据的运算过程。

 

java虚拟机栈会抛出:

StackOverflowError

OutOfMemoryError

 

5.本地方法栈。

线程私有。

本地方法栈,与,虚拟机栈,类似。

虚拟机栈,为执行java方法,而服务。

本地方法栈,为使用Native方法服务。

本地方法栈中的对象,就是不通过java编写的,可能是C++,或其他语言编写的。

 

6.java堆。

线程共享。

存放对象实例。

java堆是“垃圾收集器”负责的主要区域,因此也叫“GC堆”,(Garbage Collected Heap)

java堆内存:可以分为,“新生代”和“老年代”

 

年轻代、老年代

年轻代:垃圾回收频率多

老年代:垃圾回收频率少

 

年轻代,分为:Eden区(占80%的空间),survivor区(占20%的空间)

survivor区又分为:from区、to区,各占10%。

 

一般情况下,新生的“对象”分配在“Eden区”,当Eden区没有空间分配时,jvm将发起一次Minor

GC,如果对在“第一次”Minor GC后任然存活,并且能被Survivor区容纳(就是Survivor能不

能装的下),对象就会被移动到Survivor区中,并且对象年龄设为1岁(jvm给每一个对象义

了“对象年龄计数器”),对象在Survivor区中每“熬过”一次Minor GC,年龄就增加1岁,当对

象到达一定年龄(默认15岁),就会被移动到“老年代”。

对象晋升“老年代”的值可以设置:-XX:MaxTenuringThreshold=15

 

小结:长期存活的对象将进入老年代

 

让大对象直接进入老年代

大对象指:需要大量占用连续内存空间的对象、在java中一般指:很长的字符串、很长的数

组。

遇到“朝生夕灭”的“短命大对象”是最让jvm难受的一件事,所以可以让大对象直接进入老年

代,这样做的目的是避免“大对象”在Eden区、和Survivor区之间发生大量的内存复制。

虚拟机提供了一个 -XX:PretenureSizeThreshold=3145728,的参数使超过这个值“大对象”

直接在“老年代”中分配。

 

 

6.1.java堆内存结构图

菜鸟的jvm学习总结

 

7.java方法区。

线程共享。

java虚拟机规范,把“方法区” 描述为 “java堆”的一个逻辑部分。

存放,加载的类信息,常量,静态变量,及时编译后的代码

有人也把java方法区,称为 ”永久代“,也就是数据永久存在。

 

8.运行时常量池。

运行时常量池 ,是,方法区的,一部分。

运行时常量池,用于存放编译期间解析,的各种“字面量”和“符号引用”,还有类的版本,字段,方法名,接口,等。

常量,并不一定只有编译期间才产生,运行期间也可以将新的常量放入运行时常量池。String类的intern()方法就是如此。

 

9,直接内存。

就是cup直接提供的物理内存。

jdk1.8有个“元空间”的概念,“元空间”就是jvm中”方法区“的具体实现,而在jdk1.8以前,方法区又被称作”永久代“。

这么说,而在jdk1.8以前,方法区中存放的是,类信息、静态变量、常量,这些信息理论上来说

是不可以被垃圾回收的,所有称“方法区”为“永久代”,他占用的内存空间是java堆中的内存空间。

jdk1.8后“元空间”,占用的内存空间是向cup申请的。

 

10.对象的内存分布。

三部分:

对象头、实例数据、对齐填充:

 

对象头第一部分信息:

用于存储对象自身运行时的数据,如hashCode、GC分代年龄、锁状态,线程持有锁

对象头第二部分信息:

存储 类型指针,就是对象指向他的类的元数据的指针,虚拟机通过这个指针来确定对象是哪

个类的实例。

实例数据:

就是对象真正存储的有效信息,

对齐填充:

仅仅起到占位符的作用,

HotSpot VM的自动内存管系统,要求对象起始地址大小必须是8字节的整倍数,就是说对象

的大小必须是8字节的整倍数,因此当对象实例数据没有对齐时(也就是没有满足8字节的整

数倍时),就需要对齐填充来补全。

 

11.对象访问定位符。

使用句柄、直接指针。

 

句柄:

java会从堆中会划分一块内存作为“句柄池”,jvm栈中“reference”存放的是对象句柄的地址,

而句柄中。

包含了对象“实例数据”、“类型数据”的地址信息。

优势:reference中储存的句柄地址是稳定的,在对象被移动时(在垃圾回收时对象移动是非

常普遍的),只要修改句柄中的实例数据的指针,而reference本身不需要修改。

菜鸟的jvm学习总结

直接指针:

jvm栈“reference”中直接存放的是对象地址。

优势:速度快,它节省了一次指针定位的开销。

菜鸟的jvm学习总结

 

14.jvm如何调优

尽可以能,少执行GC

让“大对象”直接进入老年代

 

15.Minor GC 、 和 Full GC

Minor GC:在新生带中发生“垃圾回收”动作,因为大多数java对象具有“朝生夕灭”的特性,所有

Minor GC发生非常频繁,回收速度也比较快。

Full GC:在“老年代”中发生的GC,比Minor GC要慢10倍。

相关文章: