Java内存机制详解|JVM初步
[TOC]
JVM
JVM执行引擎
- 解释器
- JIT(Just In Time),优先次执行的字节码会编译成本地的机器代码,被缓存在系统中,以后可以随时调用
- 自适应的优化器,虚拟机开始的时候解释字节码CodeGo.net,但是会监控运行中程序的活动,并记录下使用最频繁的代码段,虚拟机会把这些活动最频繁的代码段编译成本地代码。还有一种虚拟机是由硬件芯片构成,它用本地方法执行java字节码
JVM程序执行过程
- 加载
.class
文件 - 管理分配内存
- 执行垃圾收集
JVM生命周期
- 启动
启动一个Java 程序时,一个JVM 实例就产生了,任何一个又有public static void main(String[] args)
函数的class 文件都可以作为JVM 实例运行的起点。 - 运行
main()
作为该程序初始线程的起点,任何其他线程均由该线程启动。JVM 内部有两种线程:守护线程和非守护线程,main()
属于非守护线程,守护线程通常由JVM 自己使用,java 程序也可以表明自己创建的线程是守护线程。 - 消亡
当程序中的所有非守护线程都终止时,JVM 才退出;若安全管理器允许,程序也可以使用Runtime类或者System.exit()来退出。
JVM的逻辑内存模型
(重点重点[敲黑板],仔细查看外链博客[敲黑板])
691
方法区:方法区(Method Area)与Java 堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然Java 虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做Non-Heap(非堆),目的应该是与Java 堆区分开来。
要注意方法区单独开辟,不同于堆内存,意在一些类的公共的方法可以共享,堆内对象还有引用指向方法区。
运行时常量池:运行时常量池(Runtime Constant Pool)是方法区的一部分。Class 文件中除了有类的版本、字段、方法、接口等描述等信息外。还有一项信息是常量池(Constant PoolTable),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。
常量池(ConstantPool):常量池在编译期间就将一部分数据存放于该区域,包含基本数据类型如int、long等和对象类型String、数组等并以final声明的常量值。特别注意的是对于运行期位于栈中的String常量的值可以通过 String.intern()方法将该值置入到常量池中。
JVM体系结构
1487
内存分配及变量存储位置(堆、栈、方法区常量池、方法区静态区)
返回值:会在栈空间中临时开辟一块空间临时存放,在方法执行完成后消失。
JVM原理
1805
堆内存和栈内存
栈内存
当在一段代码块定义一个变量时,Java 就在栈中为这个变量分配内存空间。栈中主要存放一些基本类型的变量(int
, short
, long
, byte
, float
,double
, boolean
, char
)和对象句柄。
栈有一个很重要的特殊性,就是存在栈中的数据可以共享。
堆内存
堆内存用来存放由new 创建的对象和数组
eg
假设我们同时定义:int a = 3;
int b = 3;
编译器先处理int a = 3;首先它会在栈中创建一个变量为a 的引用,然后查找栈中是否有3 这个值,如果没找到,就将3 存放进来,然后将a 指向3。接着处理int b = 3;在创建完b 的引用变量后,因为在栈中已经有3 这个值,便将b 直接指向3。这样,就出现了a 与b 同时均指向3 的情况。这时,如果再令a=4;那么编译器会重新搜索栈中是否有4 值,如果没有,则将4 存放进来,并令a 指向4;如果已经有了,则直接将a 指向这个地址。因此a 值的改变不会影响到b 的值。要注意这种数据的共享与两
个对象的引用同时指向一个对象的这种共享是不同的,因为这种情况a 的修改并不会影响到b,它是由编译器完成的,它有利于节省空间。而一个对象引用变量修改了这个对象的内部状态,会影响到另一个对象引用变量。
String 是一个特殊的包装类数据。可以用:String str = new String("abc");
String str = "abc";
两种的形式来创建,第一种是用new()
来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。而第二种是先在栈中创建一个对String 类的对象引用变量str,然后查找栈中有没有存放"abc"
,如果没有,则"abc"
存放进栈,并令str 指向"abc"
,如果已经有"abc"
则直接令str 指向"abc"
。
JVM 垃圾回收
GC (Garbage Collection)的基本原理:
将内存中不再被使用的对象进行回收,GC 中用于回收的方法称为收集器,由于GC 需要消耗一些资源和时间,Java 在对对象的生命周期特征进行分析后,按照新生代、旧生代的方式来对对象进行收集,以尽可能的缩短GC 对应用造成的暂停。
java 虚拟机会在6 种情况下创建一个对象
- 创建类的新实例
- 调用类中声明的静态方法
- 操作类或接口中声明的非常量静态字段
- 调用Java API 中特定的反射方法
- 初始化一个类的子类
- 制定一个类作为Java 虚拟机启动时的初始化类