JVM相关知识和gc过程

java虚拟机包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域。jvm屏蔽了与具体操作系统平台相关的信息,使java程序只需生成在java虚拟机上运行的目标代码(字节码),就可以在多平台上不加修改地运行。jvm在执行字节码时,实际上最终还是把字节码解释称具体平台上的机器指令执行。

JVM由哪些部分组成

1、Class Loader 类加载器

类加载器的作用是加载类文件到内存。编写的.java文件,通过javac编译成class文件,由Class loader加载到内存中。

2、Execution engine 执行引擎

执行引擎也叫做解释器(interpreter),负责解释命令,提交操作系统执行。

3、Native Interface 本地接口

早期为了调用C/C++代码而开发的

4、Runtime data erea 运行数据区

运行数据区是整个JVM的重点。我们所写的程序都被加载到这里,之后才开始运行,Java生态系统如此的繁荣,得益于该区域的优良自治。

JVM的内存管理

1、Stack 栈

栈也叫栈内存,是Java程序的运行区,是在线程创建时创建的,它的生命周期跟随线程的生命周期,线程结束栈内存也就释放,对于栈来说,不存在垃圾回收的问题,只要线程一结束,该栈就over。

栈中的数据都是以栈帧(Stack Frame)的格式存在,栈帧是一个内存区块,是一个有关方法(Method)和运行期数据的数据集。这块的具体看下面参考的文章。

2、Heap 堆

对于绝大多少应用来说,堆是jvm管理的最大的一块内存。一个jvm实例只会有一个堆内存,它是线程共享的。

先描述一下,堆内存是如何管理的。

首先堆内存分为新生区(Young Generation Space)、养老区(Tenure Generation Space)和永久区(Permanent Space)三个区,新生区又分为伊甸区(Eden Space)、幸存0区(Survivor 0 Space)和幸存1区(Survivor 2 Space)。

区分新生区和养老区是垃圾回收的需要,因为GC是需要消耗资源和时间的,为什么尽可能缩短GC对应用运行的暂停,所以才区分的。新生区中的对象存活时间比较短,养老区中的对象存活时间比较长,垃圾回收时,新生区回收量大回收效果好,养老区回收对象不会太多。

那为什么新生区又分为这三个区呢?这是回收策略决定的,新生区回收量大,也就意味着,幸存下来的对象不多,可以采用复制算法进行回收,具体做法就是伊甸区满了垃圾回收时,把不能回收的复制到幸存0区,这样伊甸区整个就能被回收了,如果幸存0区也满了,对0区进行回收,把幸存对象移到幸存1区,如果幸存1区也满了,进行回收,把幸存对象移到养老区。如果养老区也需要进行回收时,就不能采用复制算法了,因为存活对象会比较多,所以采用整理标记清除算法。一般池对象都在养老区活跃。

永久存储区是一个常驻内存的区域,用于存放jdk自身所携带的Class、Interface的元数据,也就是说它存储的是运行环境必须的类信息,被转载进此区域的数据是不会被垃圾回收器回收的,关闭jvm才会释放此区域所占用内存。

类加载器加载进来的类、方法和常变量也是放到堆内存中。具体放哪里我目前还不清楚,类加载机制也是一个知识点,以后有机会研究。

3、方法区

方法区是被所有线程共享,该区域保存所有字段和方法字节码,以及一些特殊方法如构造函数,接口代码也在此定义。

属于共享内存区域,存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

上面表述是两篇文章中说的,有些不一样,不过可以肯定是:方法区是线程共享的,至少保存了方法字节码。

存放了所加载的类信息(名称、修饰符等)、类中的静态变量、类中定义为final类型的常量、类中的Field信息、类中的方法信息;通过class对象中的getName等方法来获取信息时,实际这些数据是来源于方法区,方法区是全局共享的。

4、PC Register (Program counter register) 程序计数器

说白了就是一个指针,是为了让执行引擎找到要执行的方法字节码。这个是和线程相关的。

 

 

(1)字节码是什么?它到底是什么样的?

(2)说说对jvm中的栈是理解

        之前,我只知道栈是存一些局部变量的,其它的一无所知。从作用来说,jvm中的栈是描述java方法执行的内存模型:每个方法在执行时都会创建一个栈帧存储局部变量、操作数栈、动态链接和方法出入口等信息。每个方法从调用直至执行结束,就对应着一个栈帧从内存栈入栈到出栈的过程。内存栈的生命周期和线程生命周期一致。

 

开发中一直有个疑问,在方法中new出来的局部对象是怎么被释放掉的呢?

我们知道一个对象要被释放,要么没有任何引用指向它,要么是一个循环引用形成孤岛,gc的时候,这些对象就能够被回收了。方法中的局部对象,不会形成循环引用,它要被释放,只能是指向它的引用没有了。可是我们写代码不会手动把局部引用置为null呀,那是怎么做到的呢?

要说明这个问题,那就需要涉及到jvm的栈内存机制了,看上面的栈说明,一个方法被调用时,就会生成一个stack frame压入栈,这个stack frame中保存本地变量,也就是有个局部变量表,这里面就有局部引用变量。方法被调用结束后,stack frame就会被pop然后销毁掉,那么指向局部对象的局部引用变量被销毁了,等gc的时候,局部对象机会被回收。

java 局部变量回收的问题

 

 

需要复习的内容:

Android的进程是怎么起来的?Android中的JVM是怎么样的?

华为是怎么去掉JVM的?

 

今天是JVM的生日,来了解下JVM的发展历史吧

Java虚拟机(JVM)你只要看这一篇就够了!

两个互相引用对象的垃圾回收

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值