JVM的GC算法/类加载机制

一.JAVA中的内存划分

这里写图片描述
上面这张图就是jvm运行时的状态。具体划分为如下5个内存空间:(非常重要)
- 程序计数器:保证线程切换后能恢复到原来的执行位置,每一个线程都有一个独立的程序计数器,在线程创建时创建,指向下一条指令的地址.(如果线程执行的是本地方法,则初始化为undefined)
- 虚拟机栈:(栈内存)为虚拟机执行java方法服务: 每个方法被调用的时候都会创建一个栈帧,用于存储局部变量表、操作栈、动态链接、方法出口等信息。局部变量表存放的是:编译期可知的基本数据类型、对象引用类型。
- 本地方法栈:为虚拟机执使用到的Native方法服务
- 堆内存:存放所有new出来的东西,几乎所有对象都存储在这里.堆是GC算法的主要工作区域
- 方法区:存储被虚拟机加载的类信息、常量、静态常量、静态方法等。 (也叫做永久代Permanent Generation)
- 运行时常量池(方法区最重要的一部分)

二.JAVA对象在内存中的状态

1)可达的/可触及的:根搜索算法中从根节点可以触及到这个对象
2)可恢复的:涉及finalize()方法

3)不可达的:该对象不被任何变量引用,且finalize()方法也没有使它变成可达的状态

三.根搜索算法

首先可以作为GC Root的对象:
1、栈(栈帧中的本地变量表)中引用的对象。
2、方法区中的静态成员。
3、方法区中的常量引用的对象(全局变量)
4、本地方法栈中JNI(一般说的Native方法)引用的对象。


此处为补充说明,学习所用。

问题:JAVA引用与堆、栈。
1、栈: 存放基本数据类型及对象变量的引用,对象本身不存放于栈中而是存放于堆中
(1)基础类型 byte (8位)、boolean (1位)、char (16位)、int (32位)、short (16位)、float (32位)、double (64位)、long (64位)
(2)java代码作用域中定义一个变量时,则java就在栈中为这个变量分配内存空间,当该变量退出该作用域时,java会自动释放该变量所占的空间

2、堆: new操作符的对象
(1)new创建的对象和数组
(2)在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理
(3)静态域:static定义的静态成员变量
(4)常量池:存放常量

举例:
1 String a = “hello”; //先在栈中创建一个对String类的对象引用变量a,然后通过符号引用去字符串常量池里找有没有”hello”,如果没有,则将"hello"存放进字符串常量池 ,并令a指向"hello",如果已经有"hello"则直接将a指向"hello"这句话原文作者理解有误。
在java中,常量池有三个:全局字符串池(string pool也有叫做string literal pool)class文件常量池(class constant pool)运行时常量池(runtime constant pool)
有关这三个常量池的定义详见:http://tangxman.github.io/2015/07/27/the-difference-of-java-string-pool/
这里要说的是本例中,在查找的时候会直接找到运行时常量池里的”hello”,java中规定字符串字面量(即将字符串写死,就是几个字符)会直接放入class文件常量池中,在类加载到内存中的时候,jvm会将class常量池放入运行时常量池中,也就是说,”hello”即使第一次使用,也是直接可以从常量池中找到并复用。并不需要向常量池中增加(想常量池中增加涉及到intern方法)

2 String b = “hello”; //先在栈中创建一个对String类的对象引用变量b,然后通过符号引用去字符串常量池里找有没有”hello”,因为之前在常量池中已经有”hello”,所以直接将b指向”hello” –> 因为不需要在常量池产生”hello”

3 String newA = new String(“hello”); //先在栈中创建一个对String类的对象引用变量newA,然后new()操作会在heap堆中产生一个新的对象”hello”,并将newA指向堆中的”hello”,同时检查String pool常量池中是否有对象”hello”,如果没有也产生一个对象”hello”,如果有则不产生,因为这里之前已经在常量池中产生过了

4 String newB = new String(“hello”); //因为new每次都会保证在heap堆内存中产生新的对象,并将栈中的引用指向对应的堆中的地址,所以此语句同上一条的处理

参考博客:http://blog.csdn.net/chenyongtu110/article/details/49339783


回到正题:
从gc root开始的引用链,可以到达的对象则为可达的。这就是根搜索算法。基于此,出现了垃圾搜集的三种算法。

三.垃圾回收算法

详见:http://geek.csdn.net/news/detail/236894 写的很清楚,若以后重新学习有了更好的总结再添加。

类加载机制

在java中,类型信息在运行时(Runtime)是由Class对象表示的,它包含了与类有关的信息。

1、类加载器:

用来加载字节码文件(xxx.class)。未经过编译的源文件为.java文件,经过编译生成.class文件,再由类加载器加载字节码文件生成相应的字节码对象(class对象)

2、类加载器的种类:

(1)BootStrap:引导类加载器,加载JRE/lib/rt.jar
(2)ExtClassLoader:扩展类加载器,加载JRE/lib/ext/*.jar
(3)AppClassLoader:应用类加载器,加载第三方jar包以及自己编写的类。

3、类会在什么时候加载?

所有的类都是在对其第一次使用时动态加载到JVM中的。当程序创建一个对类的静态成员的引用时(个人理解:即调用 .方法 或 .属性),就会加载这个类。

tips:在使用new操作符创建类的新对象也会被当作对类的静态成员的使用!由此也能反向推出构造器也是类的静态方法,即使在构造器之前并没有使用static关键字。

4、类在什么时候会被初始化?

(1)实例通过使用new()关键字创建或者使用class.forName()反射,但它有可能导致ClassNotFoundException。
(2)类的静态方法被调用
(3)类的静态域被赋值
(5)静态域被访问,而且它不是常量

5、类的卸载(释放)——不理解,先记下

在满足下列条件时:
(1)该类所有的实例已经都被回收,java堆中不存在该类的任何实例。
(2)加载该类的类加载器已经被回收。
(3)该类对应的java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法。
如果以上三个条件全部满足,jvm就会在方法区垃圾回收的时候对类进行卸载,类的卸载过程其实就是在方法区中清空类信息,java类的整个生命周期就结束了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值