JVM知识点一
1.java虚拟机是什么
java虚拟机缩写JVM(java Virtual Machine)。它是一种基于计算机设备的的规范,是一台虚拟机,即虚拟的计算机。JVM屏蔽了具体操作平台的信息,通过JVM可以,java实现了平台无关性,java语言在不同平台上运行时不需要重新编译。因而能实现一次编译多次运行。
2.JRE和JDK
JRE : Java Runtime Environment ,JRE=虚拟机平台+虚拟机(JVM),类似于电脑上的VMWare+ubuntu
JDK: Java Develop Kit ,java 的开发工具包 ,jdk本体是java程序,依赖于jre,
3.虚拟机结构
JVM主要包括:方法区、堆、虚拟机栈、本地方法栈、程序计数器。其中,方法区和堆是所有线程共享的数据区,本地方法栈,虚拟机栈,程序计数器是线程私有的。
方法区
方法区属于线程共享的区域。用于存储已经被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码数据等。这块区域的内存回收主要为常量池的回收和类型的卸载。这个区域回收处理不善会导致严重的内存泄漏。当方法区无法满足内存分配时也会抛出OutOfMemoryError。
堆
java堆是被所有线程共享的一块区域,在虚拟机启动时创建,目的为了存放对象实例,几乎所有的对象实例都在这里分配内存。java堆是垃圾收集器管理的主要区域,java堆划分为新生代和老年代,新生代又划分为Eden空间,From Survivor空间,To Survivor空间。不同的堆区有不同的垃圾回收策略,因为不同的对象的生命周期不一样,采用分代回收策略便于提高垃圾回收效率。
新生代采用Minor GC,所采用的是复制算法。老年代采用的是Full GC ,所采用的的是标记-清除算法。
新生代对象回收过程:当对象在 Eden ( 包括一个 Survivor 区域,这里假设是 from 区域 ) 出生后,在经过一次 Minor GC 后,如果对象还存活,并且能够被另外一块 Survivor 区域所容纳( 上面已经假设为 from 区域,这里应为 to 区域,即 to 区域有足够的内存空间来存储 Eden 和 from 区域中存活的对象 ),则使用复制算法将这些仍然还存活的对象复制到另外一块 Survivor 区域 ( 即 to 区域 ) 中,然后清理所使用过的 Eden 以及 Survivor 区域 ( 即 from 区域 ),并且将这些对象的年龄设置为1,以后对象在 Survivor 区每熬过一次 Minor GC,就将对象的年龄 + 1,当对象的年龄达到某个值时 ( 默认是 15 岁,可以通过参数 -XX:MaxTenuringThreshold 来设定 ),这些对象就会成为老年代。
栈和虚拟机栈
栈是线程私有的,声明周期和线程相同,虚拟机栈描述java方法执行的内存模型,每个方法被执行时都会创建一个栈帧,用来存储局部变量表,操作数栈,动态链接,方法出口等信息。
局部变量数组存储八个基本数据类型,对象应用,returnAddress类型。操作数栈在执行字节码指令时会被用到,这种方式类似于原生的cpu寄存器,大部分JVM把时间花费在操作栈的花费上,操作栈和局部变量数组会频繁的交换数据。
动态连接控制着运行时常量池和栈帧的连接。所有方法和类的引用都会被当作符号的引用存在常量池中。符号引用是实际上并不指向物理内存地址的逻辑引用。JVM 可以选择符号引用解析的时机,一种是当类文件加载并校验通过后,这种解析方式被称为饥饿方式。另外一种是符号引用在第一次使用的时候被解析,这种解析方式称为惰性方式。无论如何 ,JVM 必须要在第一次使用符号引用时完成解析并抛出可能发生的解析错误。绑定是将对象域、方法、类的符号引用替换为直接引用的过程。绑定只会发生一次。一旦绑定,符号引用会被完全替换。如果一个类的符号引用还没有被解析,那么就会载入这个类。每个直接引用都被存储为相对于存储结构(与运行时变量或方法的位置相关联的)偏移量。
程序计数器
程序计数器是很小的一块内存区域,可以看做是当前线程所执行字节码的行号指示器。在虚拟机的概念模型中,字节码解释器工作时就是通过改变程序计数器的值来选取下一条需要执行的字节码指令,分支,循环,跳转,异常处理,线程恢复等基础功能均依赖于程序计数器。在多线程中,每个线程都有一个独立的程序计数器,每个线程的程序计数器之间互不影响,即“线程私有”。同时,程序计数器是java虚拟机规范中唯一一个没有规定OutOfMemoryError的区域。
运行时常量池
运行时常量池是方法区的一部分,是class文件中每一个类或者接口的常量池表在运行时的表现形式。在加载类和接口到虚拟机后,就创建对应的运行时常量池。如果构造运行时常量池所需要的内存空间超过了方法区所能提供的最大值,Java虚拟机就会抛出一个OutOfMemoryError异常。
需要特别注意的是,运行时常量池和字符串常量池的区别,在jdk1.7之前,运行时常量池逻辑包含字符串常量池存放在方法区,此时hotspot虚拟机对方法区的实现为永久代。在JDK1.7 字符串常量池被从方法区拿到了堆中,运行时常量池剩下的东西还在方法区, 也就是hotspot中的永久代。JDK1.8 hotspot移除了永久代引入元空间(Metaspace), 这时候字符串常量池还在堆中, 运行时常量池还在方法区, 只不过方法区的实现从永久代变成了元空间(Metaspace)。
如何判断对象是否应该被收回
(1)引用计算法:对象头处维护一个counter计数器,若果对该对象被引用了,counter++,引用关系失效了counter--; 如果counter变为0,说明该对象已经废弃
(2)可达性分析:这个算法的基本思路就是通过一系列名为GC Roots的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的
(3)可以作为GCroot对象:
java虚拟机栈中的引用的对象
方法区中常量应用的对象
方法区的数据什么时候被回收
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。